Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
CPPEnum.cxx
Go to the documentation of this file.
1// Bindings
2#include "CPyCppyy.h"
3#include "CPPEnum.h"
4#include "PyStrings.h"
5#include "TypeManip.h"
6#include "Utility.h"
7
8
9//- private helpers ----------------------------------------------------------
10static PyObject* pytype_from_enum_type(const std::string& enum_type)
11{
12 if (enum_type == "char")
14 else if (enum_type == "bool")
15 return (PyObject*)&PyInt_Type; // can't use PyBool_Type as base
16 else if (strstr("long", enum_type.c_str()))
17 return (PyObject*)&PyLong_Type;
18 return (PyObject*)&PyInt_Type; // covers most cases
19}
20
21//----------------------------------------------------------------------------
22static PyObject* pyval_from_enum(const std::string& enum_type, PyObject* pytype,
24 long long llval = Cppyy::GetEnumDataValue(etype, idata);
25
26 if (enum_type == "bool") {
29 return result; // <- immediate return;
30 }
31
33 if (enum_type == "char") {
34 char val = (char)llval;
36 } else if (enum_type == "int" || enum_type == "unsigned int")
37 bval = PyInt_FromLong((long)llval);
38 else
40
41 PyObject* args = PyTuple_New(1);
42 PyTuple_SET_ITEM(args, 0, bval);
43 PyObject* result = ((PyTypeObject*)btype)->tp_new((PyTypeObject*)pytype, args, nullptr);
44 Py_DECREF(args);
45 return result;
46}
47
48
49//- enum methods -------------------------------------------------------------
50static int enum_setattro(PyObject* /* pyclass */, PyObject* /* pyname */, PyObject* /* pyval */)
51{
52// Helper to make enums read-only.
53 PyErr_SetString(PyExc_TypeError, "enum values are read-only");
54 return -1;
55}
56
57//----------------------------------------------------------------------------
59{
60 using namespace CPyCppyy;
61
62 PyObject* kls_cppname = PyObject_GetAttr((PyObject*)Py_TYPE(self), PyStrings::gCppName);
64 PyObject* obj_cppname = PyObject_GetAttr(self, PyStrings::gCppName);
66 PyObject* obj_str = Py_TYPE(self)->tp_str(self);
67
68 PyObject* repr = nullptr;
71 repr = CPyCppyy_PyText_FromFormat("(%s::%s) : (%s) %s",
74 }
77
78 if (repr) {
80 return repr;
81 }
82
83 return obj_str;
84}
85
86
87//----------------------------------------------------------------------------
88// TODO: factor the following lookup with similar codes in Convertes and TemplateProxy.cxx
89
90static std::map<std::string, std::string> gCTypesNames = {
91 {"bool", "c_bool"},
92 {"char", "c_char"}, {"wchar_t", "c_wchar"},
93 {"std::byte", "c_byte"}, {"int8_t", "c_byte"}, {"uint8_t", "c_ubyte"},
94 {"short", "c_short"}, {"int16_t", "c_int16"}, {"unsigned short", "c_ushort"}, {"uint16_t", "c_uint16"},
95 {"int", "c_int"}, {"unsigned int", "c_uint"},
96 {"long", "c_long"}, {"unsigned long", "c_ulong"},
97 {"long long", "c_longlong"}, {"unsigned long long", "c_ulonglong"}};
98
99// Both GetCTypesType and GetCTypesPtrType, rely on the ctypes module itself
100// caching the types (thus also making them unique), so no ref-count is needed.
101// Further, by keeping a ref-count on the module, it won't be off-loaded until
102// the 2nd cleanup cycle.
103static PyTypeObject* GetCTypesType(const std::string& cppname)
104{
105 static PyObject* ctmod = PyImport_ImportModule("ctypes"); // ref-count kept
106 if (!ctmod)
107 return nullptr;
108
109 auto nn = gCTypesNames.find(cppname);
110 if (nn == gCTypesNames.end()) {
111 PyErr_Format(PyExc_TypeError, "Can not find ctypes type for \"%s\"", cppname.c_str());
112 return nullptr;
113 }
114
115 return (PyTypeObject*)PyObject_GetAttrString(ctmod, nn->second.c_str());
116}
117
119{
121 if (!pyres) PyErr_Clear();
122
123 std::string underlying = pyres ? CPyCppyy_PyText_AsString(pyres) : "int";
125 if (!ct)
126 return nullptr;
127
128 return PyType_Type.tp_call((PyObject*)ct, args, kwds);
129}
130
131
132//- creation -----------------------------------------------------------------
134{
135// Create a new enum type based on the actual C++ type. Enum values are added to
136// the type by may also live in the enclosing scope.
137
138 CPPEnum* pyenum = nullptr;
139
140 const std::string& ename = scope == Cppyy::gGlobalScope ? name : Cppyy::GetScopedFinalName(scope)+"::"+name;
142 if (etype) {
143 // create new enum type with labeled values in place, with a meta-class
144 // to make sure the enum values are read-only
145 const std::string& resolved = Cppyy::ResolveEnum(ename);
149 Py_INCREF(btype);
150 PyTuple_SET_ITEM(pymetabases, 0, btype);
151
152 PyObject* args = Py_BuildValue((char*)"sO{}", (name+"_meta").c_str(), pymetabases);
154 PyObject* pymeta = PyType_Type.tp_new(Py_TYPE(pyside_type), args, nullptr);
155 Py_DECREF(args);
156
157 // prepare the base class
161
162 // create the __cpp_name__ for templates
165 PyDict_SetItem(dct, PyStrings::gCppName, pycppname);
168 PyDict_SetItem(dct, PyStrings::gUnderlying, pyresolved);
170
171 // add the __module__ to allow pickling
172 std::string modname = TypeManip::extract_namespace(ename);
173 TypeManip::cppscope_to_pyscope(modname); // :: -> .
174 if (!modname.empty()) modname = "."+modname;
175 PyObject* pymodname = CPyCppyy_PyText_FromString(("cppyy.gbl"+modname).c_str());
176 PyDict_SetItem(dct, PyStrings::gModule, pymodname);
178
179 // create the actual enum class
180 args = Py_BuildValue((char*)"sOO", name.c_str(), pybases, dct);
182 Py_DECREF(dct);
183 pyenum = ((PyTypeObject*)pymeta)->tp_new((PyTypeObject*)pymeta, args, nullptr);
184
185 // add pythonizations
186 Utility::AddToClass(
188 ((PyTypeObject*)pyenum)->tp_repr = enum_repr;
189 ((PyTypeObject*)pyenum)->tp_str = ((PyTypeObject*)pyside_type)->tp_repr;
190
191 // collect the enum values
193 for (Cppyy::TCppIndex_t idata = 0; idata < ndata; ++idata) {
197 PyObject_SetAttr(val, PyStrings::gCppName, pydname);
199 Py_DECREF(val);
200 }
201
202 // disable writing onto enum values
203 ((PyTypeObject*)pymeta)->tp_setattro = enum_setattro;
204
205 // final cleanup
206 Py_DECREF(args);
208
209 } else {
210 // presumably not a class enum; simply pretend int
213 }
214
215 return pyenum;
216}
static PyObject * enum_repr(PyObject *self)
Definition CPPEnum.cxx:58
static std::map< std::string, std::string > gCTypesNames
Definition CPPEnum.cxx:90
static PyObject * pytype_from_enum_type(const std::string &enum_type)
Definition CPPEnum.cxx:10
static PyObject * enum_ctype(PyObject *cls, PyObject *args, PyObject *kwds)
Definition CPPEnum.cxx:118
static PyObject * pyval_from_enum(const std::string &enum_type, PyObject *pytype, PyObject *btype, Cppyy::TCppEnum_t etype, Cppyy::TCppIndex_t idata)
Definition CPPEnum.cxx:22
static PyTypeObject * GetCTypesType(const std::string &cppname)
Definition CPPEnum.cxx:103
static int enum_setattro(PyObject *, PyObject *, PyObject *)
Definition CPPEnum.cxx:50
#define Py_TYPE(ob)
Definition CPyCppyy.h:196
#define CPyCppyy_PyText_FromStringAndSize
Definition CPyCppyy.h:85
#define CPyCppyy_PyText_AsString
Definition CPyCppyy.h:76
#define CPyCppyy_PyText_FromFormat
Definition CPyCppyy.h:80
#define CPyCppyy_PyText_Type
Definition CPyCppyy.h:94
#define CPyCppyy_PyText_FromString
Definition CPyCppyy.h:81
_object PyObject
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
char name[80]
Definition TGX11.cxx:110
const_iterator end() const
PyObject * gUnderlying
Definition PyStrings.cxx:40
CPPEnum * CPPEnum_New(const std::string &name, Cppyy::TCppScope_t scope)
Definition CPPEnum.cxx:133
PyObject CPPEnum
Definition CPPEnum.h:9
size_t TCppIndex_t
Definition cpp_cppyy.h:24
RPY_EXPORTED TCppScope_t gGlobalScope
Definition cpp_cppyy.h:53
RPY_EXPORTED std::string ResolveEnum(const std::string &enum_type)
RPY_EXPORTED long long GetEnumDataValue(TCppEnum_t, TCppIndex_t idata)
void * TCppEnum_t
Definition cpp_cppyy.h:20
RPY_EXPORTED std::string GetScopedFinalName(TCppType_t type)
RPY_EXPORTED std::string GetEnumDataName(TCppEnum_t, TCppIndex_t idata)
size_t TCppScope_t
Definition cpp_cppyy.h:18
RPY_EXPORTED TCppIndex_t GetNumEnumData(TCppEnum_t)
RPY_EXPORTED TCppEnum_t GetEnum(TCppScope_t scope, const std::string &enum_name)