-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathpythonHelpers.hpp
More file actions
142 lines (125 loc) · 3.3 KB
/
pythonHelpers.hpp
File metadata and controls
142 lines (125 loc) · 3.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#pragma once
#include "cstring.h"
#include <Python.h>
#include <cassert>
#include <frameobject.h>
#include <string>
#include <type_traits>
namespace scorepy
{
struct retain_object_t
{
};
struct adopt_object_t
{
};
/// Marker to indicate that an owner is added, i.e. refCnt is increased
constexpr retain_object_t retain_object{};
/// Marker to take over ownership, not touching the refCnt
constexpr adopt_object_t adopt_object{};
/// Slim, owning wrapper over a PyObject*
/// Decays implictely to a PyObject*
class PyRefObject
{
PyObject* o_;
public:
explicit PyRefObject(PyObject* o, adopt_object_t) noexcept : o_(o)
{
}
explicit PyRefObject(PyObject* o, retain_object_t) noexcept : o_(o)
{
Py_XINCREF(o_);
}
PyRefObject(PyRefObject&& rhs) noexcept : o_(rhs.o_)
{
rhs.o_ = nullptr;
}
PyRefObject& operator=(PyRefObject&& rhs) noexcept
{
o_ = rhs.o_;
rhs.o_ = nullptr;
return *this;
}
~PyRefObject() noexcept
{
Py_XDECREF(o_);
}
operator PyObject*() const noexcept
{
return o_;
}
};
namespace detail
{
template <typename TFunc>
struct ReplaceArgsToPyObject;
template <typename TFunc>
using ReplaceArgsToPyObject_t = typename ReplaceArgsToPyObject<TFunc>::type;
} // namespace detail
/// Cast a function pointer to a python-bindings compatible function pointer
/// Replaces all Foo* by PyObject* for all types Foo that are PyObject compatible
template <typename TFunc>
auto cast_to_PyFunc(TFunc* func) -> detail::ReplaceArgsToPyObject_t<TFunc>*
{
return reinterpret_cast<detail::ReplaceArgsToPyObject_t<TFunc>*>(func);
}
inline CString get_string_from_python(PyObject& o)
{
#if PY_MAJOR_VERSION >= 3
Py_ssize_t len;
const char* s = PyUnicode_AsUTF8AndSize(&o, &len);
return CString(s, len);
#else
const char* s = PyString_AsString(&o);
return CString(s);
#endif
}
/// Pair of a C-String and it's length useful for PyArg_ParseTuple with 's#'
/// Implicitely converts to CString.
struct PythonCString
{
const char* s;
Py_ssize_t l;
operator CString() const
{
assert(s);
return CString(s, l);
}
};
/// Return the module name the frame belongs to.
/// The pointer is valid for the lifetime of the frame
CString get_module_name(const PyFrameObject& frame);
/// Return the file name the frame belongs to
/// The returned CString is valid until the next call to this function
CString get_file_name(const PyFrameObject& frame);
// Implementation details
namespace detail
{
template <typename>
struct make_void
{
typedef void type;
};
template <typename T>
using void_t = typename make_void<T>::type;
template <class T, class = void>
struct IsPyObject : std::false_type
{
};
template <class T>
struct IsPyObject<T*> : IsPyObject<T>
{
};
template <class T>
struct IsPyObject<T, void_t<decltype(std::declval<T>().to_PyObject())>> : std::true_type
{
};
template <typename TResult, typename... TArgs>
struct ReplaceArgsToPyObject<TResult(TArgs...)>
{
template <typename T>
using replace = typename std::conditional<IsPyObject<T>::value, PyObject*, T>::type;
using type = TResult(replace<TArgs>...);
};
} // namespace detail
} // namespace scorepy