Skip to content

Instantly share code, notes, and snippets.

@llllllllll
Last active February 21, 2016 02:07
Show Gist options
  • Save llllllllll/7efaeae829c79032b0dd to your computer and use it in GitHub Desktop.
Save llllllllll/7efaeae829c79032b0dd to your computer and use it in GitHub Desktop.
#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__), \
)
}
In [1]: from cpp.test import func
In [2]: func(12, True, "test")
12 1 test
#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);
}
};
#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