94 const std::string& derivedName,
const BaseInfos_t& base_infos,
const AllCtors_t& ctors,
95 std::ostringstream& code,
const CtorInfos_t& methods = CtorInfos_t{},
size_t idx = 0)
97 if (idx < ctors.size()) {
98 for (
const auto& method : ctors[idx]) {
101 for (
size_t i = argsmin; i <= argsmax; ++i) {
102 CtorInfos_t methods1{methods};
103 methods1.emplace_back(method, i);
109 code <<
" " << derivedName <<
"(";
112 std::vector<size_t> arg_tots; arg_tots.reserve(methods.size());
113 for (Ctors_t::size_type i = 0; i < methods.size(); ++i) {
114 const auto& cinfo = methods[i];
115 if (i != 0 && (arg_tots.back() || 1 < arg_tots.size())) code <<
", ";
116 size_t nArgs = cinfo.second;
117 arg_tots.push_back(i == 0 ? nArgs : nArgs+arg_tots.back());
119 if (i != 0) code <<
"__cppyy_internal::Sep*";
120 size_t offset = (i != 0 ? arg_tots[i-1] : 0);
121 for (
size_t j = 0; j < nArgs; ++j) {
122 if (i != 0 || j != 0) code <<
", ";
129 for (BaseInfos_t::size_type i = 0; i < base_infos.size(); ++i) {
130 if (i != 0) code <<
", ";
131 code << base_infos[i].bname <<
"(";
132 size_t first = (i != 0 ? arg_tots[i-1] : 0);
133 for (
size_t j = first; j < arg_tots[i]; ++j) {
134 if (j != first) code <<
", ";
137 if (isRValue) code <<
"std::move(";
139 if (isRValue) code <<
")";
175 if (!PyTuple_Check(bases) || !PyTuple_GET_SIZE(bases) || !dct || !PyDict_Check(dct)) {
176 err <<
"internal error: expected tuple of bases and proper dictionary";
181 err <<
"failed to include Python.h";
186 const Py_ssize_t nBases = PyTuple_GET_SIZE(bases);
187 BaseInfos_t base_infos; base_infos.reserve(nBases);
188 for (
Py_ssize_t ibase = 0; ibase < nBases; ++ibase) {
195 err <<
"base class is incomplete";
206 if (PyErr_WarnEx(PyExc_RuntimeWarning, (
char*)(
"class \""+bname+
"\" has no virtual destructor").c_str(), 1) < 0)
210 base_infos.emplace_back(
215 bool isDeepHierarchy = klass->
fCppType && base_infos.front().btype != klass->
fCppType;
219 static int counter = 0;
220 std::ostringstream osname;
221 osname <<
"Dispatcher" << ++counter;
222 const std::string& derivedName = osname.str();
225 std::ostringstream code;
228 code <<
"namespace __cppyy_internal {\n"
229 <<
"class " << derivedName <<
" : ";
230 for (BaseInfos_t::size_type ibase = 0; ibase < base_infos.size(); ++ibase) {
231 if (ibase != 0) code <<
", ";
232 code <<
"public ::" << base_infos[ibase].bname_scoped;
235 if (!isDeepHierarchy)
236 code <<
"protected:\n CPyCppyy::DispatchPtr _internal_self;\n";
243 if (PyMapping_HasKeyString(dct, (
char*)
"__destruct__")) {
244 code <<
" virtual ~" << derivedName <<
"() {\n"
245 "PyGILState_STATE state = PyGILState_Ensure();\n"
246 " PyObject* iself = (PyObject*)_internal_self;\n"
247 " if (!iself || iself == Py_None)\n"
249 " Py_INCREF(iself);\n"
250 " PyObject* mtPyName = PyUnicode_FromString(\"__destruct__\");\n"
251 " PyObject* pyresult = PyObject_CallMethodObjArgs(iself, mtPyName, NULL);\n"
252 " Py_DECREF(mtPyName);\n Py_DECREF(iself);\n";
256 code <<
" if (!pyresult) PyErr_Print();\n"
257 " else { Py_DECREF(pyresult); }\n"
258 " PyGILState_Release(state);\n"
261 code <<
" virtual ~" << derivedName <<
"() {}\n";
266 PyObject* items = PyDict_Items(dct);
267 for (
Py_ssize_t i = 0; i < PyList_GET_SIZE(items); ++i) {
268 PyObject* value = PyTuple_GET_ITEM(PyList_GET_ITEM(items, i), 1);
269 if (PyCallable_Check(value))
270 PyDict_SetItem(clbs, PyTuple_GET_ITEM(PyList_GET_ITEM(items, i), 0), value);
278 std::set<std::string> protected_names;
281 int has_default = 0, has_cctor = 0, has_ctors = 0, has_tmpl_ctors = 0;
282 AllCtors_t ctors{base_infos.size()};
283 for (BaseInfos_t::size_type ibase = 0; ibase < base_infos.size(); ++ibase) {
284 const auto& binfo = base_infos[ibase];
287 bool cctor_found =
false, default_found =
false, any_ctor_found =
false;
292 any_ctor_found =
true;
295 if (nreq == 0) default_found =
true;
296 else if (!cctor_found && nreq == 1) {
301 ctors[ibase].push_back(method);
308 int contains = PyDict_Contains(dct, key);
316 protected_names.insert(mtCppName);
321 if (i != 0) code <<
", ";
326 code <<
"{\n return " << binfo.bname <<
"::" << mtCppName <<
"(";
328 if (i != 0) code <<
", ";
339 if (PyDict_DelItem(clbs, key) != 0)
345 if (base_infos.size() == 1) {
349 any_ctor_found =
true;
357 if (cctor_found || (!cctor_found && !any_ctor_found)) has_cctor += 1;
358 if (default_found || (!default_found && !any_ctor_found)) has_default += 1;
359 if (any_ctor_found && !has_tmpl_ctors) has_ctors += 1;
363 for (
const auto& binfo : base_infos) {
364 if (PyDict_Size(clbs)) {
366 for (
size_t ibase = 0; ibase < nbases; ++ibase) {
371 for (
Py_ssize_t i = 0; i < PyList_GET_SIZE(keys); ++i) {
373 PyObject* key = PyList_GET_ITEM(keys, i);
375 const auto&
v = FindBaseMethod(tbase, mtCppName);
379 if (PyDict_DelItem(clbs, key) != 0) PyErr_Clear();
396 if (1 < nBases && (!has_ctors || has_default == nBases))
397 code <<
" " << derivedName <<
"() {}\n";
398 if (has_cctor == nBases) {
399 code <<
" " << derivedName <<
"(const " << derivedName <<
"& other) : ";
400 for (BaseInfos_t::size_type ibase = 0; ibase < base_infos.size(); ++ibase) {
401 if (ibase != 0) code <<
", ";
402 code << base_infos[ibase].bname <<
"(other)";
404 if (!isDeepHierarchy)
405 code <<
", _internal_self(other._internal_self, this)";
408 if (has_tmpl_ctors && base_infos.size() == 1) {
410 code <<
" template<typename ...Args>\n " << derivedName <<
"(Args... args) : "
411 << base_infos[0].bname <<
"(args...) {}\n";
417 bool setPublic =
false;
418 for (
const auto& binfo : base_infos) {
423 if (dm_name !=
"_internal_self") {
425 protected_names.insert(dname);
430 code <<
" using " << binfo.bname <<
"::" << dname <<
";\n";
437 BaseInfos_t::size_type disp_inited = 0;
438 code <<
"public:\n static void _init_dispatchptr(" << derivedName <<
"* inst, PyObject* self) {\n";
439 if (1 < base_infos.size()) {
440 for (
const auto& binfo : base_infos) {
442 code <<
" " << binfo.bname <<
"::_init_dispatchptr(inst, self);\n";
453 if (disp_inited != base_infos.size())
454 code <<
" new ((void*)&inst->_internal_self) CPyCppyy::DispatchPtr{self, true};\n";
458 code <<
"\n static PyObject* _get_dispatch(" << derivedName <<
"* inst) {\n"
459 " PyGILState_STATE state = PyGILState_Ensure();\n"
460 " PyObject* res = (PyObject*)inst->_internal_self;\n"
461 " Py_XINCREF(res);\n"
462 " PyGILState_Release(state);\n"
470 err <<
"failed to compile the dispatcher code";
478 err <<
"failed to retrieve the internal dispatcher";
494 for (
const auto&
name : protected_names) {
496#if PY_VERSION_HEX < 0x30d00f0
497 PyObject* pyf = PyMapping_GetItemString(disp_dct, (
char*)
name.c_str());
500 PyMapping_GetOptionalItemString(disp_dct, (
char*)
name.c_str(), &pyf);
503 PyObject_SetAttrString((
PyObject*)klass, (
char*)
name.c_str(), pyf);
509 Py_XDECREF(disp_proxy);