diff --git a/src/CPPDataMember.cxx b/src/CPPDataMember.cxx index e632a029..73b9b585 100644 --- a/src/CPPDataMember.cxx +++ b/src/CPPDataMember.cxx @@ -307,11 +307,13 @@ PyTypeObject CPPDataMember_Type = { } // namespace CPyCppyy //- public members ----------------------------------------------------------- -void CPyCppyy::CPPDataMember::Set(Cppyy::TCppScope_t scope, Cppyy::TCppScope_t data) +void CPyCppyy::CPPDataMember::Set(Cppyy::TCppScope_t scope, Cppyy::TCppScope_t data, + intptr_t additional_offset) { fEnclosingScope = scope; fScope = data; - fOffset = Cppyy::GetDatamemberOffset(data); // XXX: Check back here // TODO: make lazy + fOffset = Cppyy::GetDatamemberOffset(data) + + additional_offset; // XXX: Check back here // TODO: make lazy fFlags = Cppyy::IsStaticDatamember(data) ? kIsStaticData : 0; const std::string name = Cppyy::GetFinalName(data); diff --git a/src/CPPDataMember.h b/src/CPPDataMember.h index 9241b4dd..65bc0ae7 100644 --- a/src/CPPDataMember.h +++ b/src/CPPDataMember.h @@ -14,7 +14,8 @@ class CPPInstance; class CPPDataMember { public: - void Set(Cppyy::TCppScope_t scope, Cppyy::TCppScope_t var); + void Set(Cppyy::TCppScope_t scope, Cppyy::TCppScope_t var, + intptr_t additional_offset=0); void Set(Cppyy::TCppScope_t scope, const std::string& name, void* address); std::string GetName(); @@ -56,12 +57,12 @@ inline bool CPPDataMember_CheckExact(T* object) //- creation ----------------------------------------------------------------- inline CPPDataMember* CPPDataMember_New( - Cppyy::TCppScope_t scope, Cppyy::TCppScope_t var) + Cppyy::TCppScope_t scope, Cppyy::TCppScope_t var, intptr_t additional_offset=0) { // Create an initialize a new property descriptor, given the C++ datum. CPPDataMember* pyprop = (CPPDataMember*)CPPDataMember_Type.tp_new(&CPPDataMember_Type, nullptr, nullptr); - pyprop->Set(scope, var); + pyprop->Set(scope, var, additional_offset); return pyprop; } diff --git a/src/ProxyWrappers.cxx b/src/ProxyWrappers.cxx index b5261ee9..0add8f87 100644 --- a/src/ProxyWrappers.cxx +++ b/src/ProxyWrappers.cxx @@ -89,10 +89,42 @@ static PyObject* CreateNewCppProxyClass(Cppyy::TCppScope_t klass, PyObject* pyba } static inline -void AddPropertyToClass(PyObject* pyclass, - Cppyy::TCppScope_t scope, Cppyy::TCppScope_t data) +void AddPropertyToClass(PyObject* pyclass, Cppyy::TCppScope_t scope, + Cppyy::TCppScope_t data, intptr_t additional_offset=0) { - CPyCppyy::CPPDataMember* property = CPyCppyy::CPPDataMember_New(scope, data); + if (!Cppyy::IsPublicData(data)) + return; + + // enum datamembers (this in conjunction with previously collected enums above) + if (Cppyy::IsEnumType(Cppyy::GetDatamemberType(data)) && + Cppyy::IsStaticDatamember(data)) { + // some implementation-specific data members have no address: ignore them + if (!Cppyy::GetDatamemberOffset(data)) + return; + + // two options: this is a static variable, or it is the enum value, the latter + // already exists, so check for it and move on if set + PyObject* eset = PyObject_GetAttrString(pyclass, + const_cast(Cppyy::GetFinalName(data).c_str())); + if (eset) { + Py_DECREF(eset); + return; + } + + PyErr_Clear(); + } + + if (strstr(Cppyy::GetDatamemberTypeAsString(data).c_str(), "anonymous struct at") || + strstr(Cppyy::GetDatamemberTypeAsString(data).c_str(), "anonymous union at")) { + std::vector datamembers = Cppyy::GetDatamembers(Cppyy::GetTypeScope(data)); + for (auto &datamember: datamembers) { + // properties (aka public (static) data members) + AddPropertyToClass(pyclass, scope, datamember, + additional_offset + Cppyy::GetDatamemberOffset(data)); + } + } + + CPyCppyy::CPPDataMember* property = CPyCppyy::CPPDataMember_New(scope, data, additional_offset); PyObject* pname = CPyCppyy_PyText_InternFromString(const_cast(property->GetName().c_str())); // allow access at the instance level @@ -371,37 +403,7 @@ static int BuildScopeProxyDict(Cppyy::TCppScope_t scope, PyObject* pyclass, cons // collect data members (including enums) std::vector datamembers = Cppyy::GetDatamembers(scope); for (auto &datamember : datamembers) { - // allow only public members - if (!Cppyy::IsPublicData(datamember)) - continue; - - // enum datamembers (this in conjunction with previously collected enums above) - if (Cppyy::IsEnumType(Cppyy::GetDatamemberType(datamember)) && Cppyy::IsStaticDatamember(datamember)) { - // some implementation-specific data members have no address: ignore them - if (!Cppyy::GetDatamemberOffset(datamember)) - continue; - - // two options: this is a static variable, or it is the enum value, the latter - // already exists, so check for it and move on if set - PyObject* eset = PyObject_GetAttrString(pyclass, - const_cast(Cppyy::GetFinalName(datamember).c_str())); - if (eset) { - Py_DECREF(eset); - continue; - } - - PyErr_Clear(); - - // it could still be that this is an anonymous enum, which is not in the list - // provided by the class - if (strstr(Cppyy::GetDatamemberTypeAsString(datamember).c_str(), "(anonymous)") != 0 || - strstr(Cppyy::GetDatamemberTypeAsString(datamember).c_str(), "(unnamed)") != 0) { - AddPropertyToClass(pyclass, scope, datamember); - continue; - } - } - - // properties (aka public (static) data members) + // properties (aka public (static) data members) AddPropertyToClass(pyclass, scope, datamember); }