Last active
February 21, 2016 02:07
-
-
Save llllllllll/7efaeae829c79032b0dd to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <array> | |
#include <tuple> | |
#include <Python.h> | |
#include "utils.h" | |
namespace pyutils { | |
template<typename T> | |
constexpr char _typeformat; | |
template<> | |
constexpr char _typeformat<const char*> = 'z'; | |
template<> | |
constexpr char _typeformat<Py_buffer> = 's'; | |
template<> | |
constexpr char _typeformat<char> = 'c'; | |
template<> | |
constexpr char _typeformat<unsigned char> = 'b'; | |
template<> | |
constexpr char _typeformat<unsigned short> = 'h'; | |
template<> | |
constexpr char _typeformat<int> = 'i'; | |
template<> | |
constexpr char _typeformat<long> = 'l'; | |
template<> | |
constexpr char _typeformat<unsigned long> = 'k'; | |
template<> | |
constexpr char _typeformat<float> = 'f'; | |
template<> | |
constexpr char _typeformat<double> = 'd'; | |
template<> | |
constexpr char _typeformat<Py_complex> = 'D'; | |
template<> | |
constexpr char _typeformat<PyObject*> = 'O'; | |
template<> | |
constexpr char _typeformat<bool> = 'p'; | |
template<typename F> | |
struct _function_traits; | |
template<typename R, typename Self, typename... Args> | |
struct _function_traits<R(Self, Args...)> { | |
using return_type = R; | |
using parsed_args_type = std::tuple<Args...>; | |
static constexpr std::size_t arity = sizeof...(Args); | |
static inline auto fmtstr() { | |
return std::array<char, arity + 1> {_typeformat<Args>..., '\0'}; | |
} | |
}; | |
template<typename F, const F &impl> | |
PyObject *_automethodwrapper(PyObject *self, PyObject *args) { | |
using f = _function_traits<F>; | |
typename f::parsed_args_type parsed_args; | |
if (!apply(PyArg_ParseTuple, | |
std::tuple_cat(std::make_tuple(args, f::fmtstr().data()), | |
tuple_refs(parsed_args)))) { | |
return NULL; | |
} | |
return apply(impl, std::tuple_cat(std::make_tuple(self), parsed_args)); | |
} | |
#define _cpp_automethod_2(f, doc) (PyMethodDef { \ | |
#f, \ | |
(PyCFunction) pyutils::_automethodwrapper<decltype(f), f>, \ | |
METH_VARARGS, \ | |
doc, \ | |
}) | |
#define _cpp_automethod_1(f) _cpp_automethod_2(f, NULL) | |
#define _cpp_automethod_dispatch(n, f, doc, macro, ...) macro | |
/* Wrap a C++ function as a python PyMethodDef structure. | |
Parameters | |
---------- | |
f : function | |
The function to wrap. | |
doc : const char*, optional | |
The docstring for the function. | |
Returns | |
------- | |
m : PyMethodDef | |
The methoddef. */ | |
#define automethod(...) \ | |
_cpp_automethod_dispatch( \ | |
,##__VA_ARGS__, \ | |
_cpp_automethod_2(__VA_ARGS__), \ | |
_cpp_automethod_1(__VA_ARGS__), \ | |
) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
In [1]: from cpp.test import func | |
In [2]: func(12, True, "test") | |
12 1 test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <Python.h> | |
#include "cpp/automethod.h" | |
static PyObject *func(PyObject *self, int a, bool b, const char *cs) { | |
std::cout << a << ' ' << b << ' ' << cs << '\n'; | |
Py_RETURN_NONE; | |
} | |
PyMethodDef methods[] = { | |
automethod(func), | |
{NULL}, | |
}; | |
PyModuleDef module = { | |
PyModuleDef_HEAD_INIT, | |
"cpp.test", | |
"", | |
-1, | |
methods, | |
}; | |
extern "C" { | |
PyMODINIT_FUNC | |
PyInit_test() { | |
return PyModule_Create(&module); | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <tuple> | |
#include <utility> | |
namespace pyutils { | |
template<std::size_t n> | |
struct Apply { | |
template<typename F, typename T, typename... A> | |
static inline auto apply(F &&f, T &&t, A&&... a) { | |
return Apply<n - 1>::apply( | |
std::forward<F>(f), | |
std::forward<T>(t), | |
std::get<n - 1>(std::forward<T>(t)), std::forward<A>(a)...); | |
} | |
}; | |
template<> | |
struct Apply<0> { | |
template<typename F, typename T, typename... A> | |
static inline auto apply(F &&f, T&&, A&&... a) { | |
return ::std::forward<F>(f)(::std::forward<A>(a)...); | |
} | |
}; | |
template<typename F, typename T> | |
inline auto apply(F &&f, T &&t) { | |
return Apply<std::tuple_size<std::decay_t<T>>::value>::apply( | |
std::forward<F>(f), std::forward<T>(t)); | |
} | |
template<typename T, std::size_t... Ixs> | |
auto _tuple_refs_impl(T &&t, std::index_sequence<Ixs...>) { | |
return std::make_tuple(&std::get<Ixs>(std::forward<T>(t))...); | |
} | |
template<typename T> | |
auto tuple_refs(T &&t) { | |
return _tuple_refs_impl( | |
std::forward<T>(t), | |
std::make_index_sequence< | |
std::tuple_size<std::remove_reference_t<T> | |
>::value>{}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment