91 const std::string& derivedName,
const BaseInfos_t& base_infos,
const AllCtors_t& ctors,
92 std::ostringstream& code,
const CtorInfos_t& methods = CtorInfos_t{},
size_t idx = 0)
94 if (idx < ctors.size()) {
95 for (
const auto& method : ctors[idx]) {
98 for (
size_t i = argsmin;
i <= argsmax; ++
i) {
99 CtorInfos_t methods1{methods};
100 methods1.emplace_back(method,
i);
106 code <<
" " << derivedName <<
"(";
109 std::vector<size_t> arg_tots; arg_tots.reserve(methods.size());
110 for (Ctors_t::size_type
i = 0;
i < methods.size(); ++
i) {
111 const auto& cinfo = methods[
i];
112 if (
i != 0 && (arg_tots.back() || 1 < arg_tots.size())) code <<
", ";
113 size_t nArgs = cinfo.second;
114 arg_tots.push_back(
i == 0 ? nArgs : nArgs+arg_tots.back());
116 if (
i != 0) code <<
"__cppyy_internal::Sep*";
117 size_t offset = (
i != 0 ? arg_tots[
i-1] : 0);
118 for (
size_t j = 0; j < nArgs; ++j) {
119 if (
i != 0 || j != 0) code <<
", ";
126 for (BaseInfos_t::size_type
i = 0;
i < base_infos.size(); ++
i) {
127 if (
i != 0) code <<
", ";
128 code << base_infos[
i].bname <<
"(";
129 size_t first = (
i != 0 ? arg_tots[
i-1] : 0);
130 for (
size_t j = first; j < arg_tots[
i]; ++j) {
131 if (j != first) code <<
", ";
134 if (isRValue) code <<
"std::move(";
136 if (isRValue) code <<
")";
172 if (!PyTuple_Check(bases) || !PyTuple_GET_SIZE(bases) || !dct || !PyDict_Check(dct)) {
173 err <<
"internal error: expected tuple of bases and proper dictionary";
178 err <<
"failed to include Python.h";
183 const Py_ssize_t nBases = PyTuple_GET_SIZE(bases);
184 BaseInfos_t base_infos; base_infos.reserve(nBases);
185 for (
Py_ssize_t ibase = 0; ibase < nBases; ++ibase) {
192 err <<
"base class is incomplete";
203 PyErr_Warn(PyExc_RuntimeWarning, (
char*)(
"class \""+bname+
"\" has no virtual destructor").c_str());
206 base_infos.emplace_back(
211 bool isDeepHierarchy = klass->
fCppType && base_infos.front().btype != klass->
fCppType;
215 static int counter = 0;
216 std::ostringstream osname;
217 osname <<
"Dispatcher" << ++counter;
218 const std::string& derivedName = osname.str();
221 std::ostringstream code;
224 code <<
"namespace __cppyy_internal {\n"
225 <<
"class " << derivedName <<
" : ";
226 for (BaseInfos_t::size_type ibase = 0; ibase < base_infos.size(); ++ibase) {
227 if (ibase != 0) code <<
", ";
228 code <<
"public ::" << base_infos[ibase].bname_scoped;
231 if (!isDeepHierarchy)
232 code <<
"protected:\n CPyCppyy::DispatchPtr _internal_self;\n";
239 if (PyMapping_HasKeyString(dct, (
char*)
"__destruct__")) {
240 code <<
" virtual ~" << derivedName <<
"() {\n"
241 " PyObject* iself = (PyObject*)_internal_self;\n"
242 " if (!iself || iself == Py_None)\n"
244 " Py_INCREF(iself);\n"
245 " PyObject* mtPyName = PyUnicode_FromString(\"__destruct__\");\n"
246 " PyObject* pyresult = PyObject_CallMethodObjArgs(iself, mtPyName, NULL);\n"
247 " Py_DECREF(mtPyName);\n Py_DECREF(iself);\n";
251 code <<
" if (!pyresult) PyErr_Print();\n"
252 " else { Py_DECREF(pyresult); }\n"
255 code <<
" virtual ~" << derivedName <<
"() {}\n";
260 PyObject* items = PyDict_Items(dct);
263 if (PyCallable_Check(
value))
264 PyDict_SetItem(clbs, PyTuple_GET_ITEM(PyList_GET_ITEM(items,
i), 0),
value);
272 std::set<std::string> protected_names;
275 int has_default = 0, has_cctor = 0, has_ctors = 0, has_tmpl_ctors = 0;
276 AllCtors_t ctors{base_infos.size()};
277 for (BaseInfos_t::size_type ibase = 0; ibase < base_infos.size(); ++ibase) {
278 const auto& binfo = base_infos[ibase];
281 bool cctor_found =
false, default_found =
false, any_ctor_found =
false;
286 any_ctor_found =
true;
289 if (nreq == 0) default_found =
true;
290 else if (!cctor_found && nreq == 1) {
295 ctors[ibase].push_back(method);
302 int contains = PyDict_Contains(dct, key);
303 if (contains == -1) PyErr_Clear();
310 protected_names.insert(mtCppName);
315 if (
i != 0) code <<
", ";
320 code <<
"{\n return " << binfo.bname <<
"::" << mtCppName <<
"(";
322 if (
i != 0) code <<
", ";
333 if (PyDict_DelItem(clbs, key) != 0)
339 if (base_infos.size() == 1) {
343 any_ctor_found =
true;
351 if (cctor_found || (!cctor_found && !any_ctor_found)) has_cctor += 1;
352 if (default_found || (!default_found && !any_ctor_found)) has_default += 1;
353 if (any_ctor_found && !has_tmpl_ctors) has_ctors += 1;
357 for (
const auto& binfo : base_infos) {
358 if (PyDict_Size(clbs)) {
360 for (
size_t ibase = 0; ibase < nbases; ++ibase) {
367 PyObject* key = PyList_GET_ITEM(keys,
i);
369 const auto&
v = FindBaseMethod(tbase, mtCppName);
373 if (PyDict_DelItem(clbs, key) != 0) PyErr_Clear();
390 if (1 < nBases && (!has_ctors || has_default == nBases))
391 code <<
" " << derivedName <<
"() {}\n";
392 if (has_cctor == nBases) {
393 code <<
" " << derivedName <<
"(const " << derivedName <<
"& other) : ";
394 for (BaseInfos_t::size_type ibase = 0; ibase < base_infos.size(); ++ibase) {
395 if (ibase != 0) code <<
", ";
396 code << base_infos[ibase].bname <<
"(other)";
398 if (!isDeepHierarchy)
399 code <<
", _internal_self(other._internal_self, this)";
402 if (has_tmpl_ctors && base_infos.size() == 1) {
404 code <<
" template<typename ...Args>\n " << derivedName <<
"(Args... args) : "
405 << base_infos[0].bname <<
"(args...) {}\n";
411 bool setPublic =
false;
412 for (
const auto& binfo : base_infos) {
417 if (dm_name !=
"_internal_self") {
419 protected_names.insert(dname);
424 code <<
" using " << binfo.bname <<
"::" << dname <<
";\n";
431 BaseInfos_t::size_type disp_inited = 0;
432 code <<
"public:\n static void _init_dispatchptr(" << derivedName <<
"* inst, PyObject* self) {\n";
433 if (1 < base_infos.size()) {
434 for (
const auto& binfo : base_infos) {
436 code <<
" " << binfo.bname <<
"::_init_dispatchptr(inst, self);\n";
447 if (disp_inited != base_infos.size())
448 code <<
" new ((void*)&inst->_internal_self) CPyCppyy::DispatchPtr{self, true};\n";
452 code <<
"\n static PyObject* _get_dispatch(" << derivedName <<
"* inst) {\n"
453 " PyObject* res = (PyObject*)inst->_internal_self;\n"
454 " Py_XINCREF(res); return res;\n }";
461 err <<
"failed to compile the dispatcher code";
469 err <<
"failed to retrieve the internal dispatcher";
485 for (
const auto&
name : protected_names) {
487 PyObject* pyf = PyMapping_GetItemString(disp_dct, (
char*)
name.c_str());
489 PyObject_SetAttrString((
PyObject*)klass, (
char*)
name.c_str(), pyf);
495 Py_XDECREF(disp_proxy);