96 const BaseInfos_t& base_infos,
97 const AllCtors_t& ctors,
98 std::ostringstream& code,
99 const CtorInfos_t& methods = CtorInfos_t{},
101 if (idx < ctors.size()) {
102 for (
const auto& method : ctors[idx]) {
105 for (
size_t i = argsmin; i <= argsmax; ++i) {
106 CtorInfos_t methods1{methods};
107 methods1.emplace_back(method, i);
114 code <<
" " << derivedName <<
"(";
117 std::vector<size_t> arg_tots;
118 arg_tots.reserve(methods.size());
119 for (Ctors_t::size_type i = 0; i < methods.size(); ++i) {
120 const auto& cinfo = methods[i];
121 if (i != 0 && (arg_tots.back() || 1 < arg_tots.size()))
123 size_t nArgs = cinfo.second;
124 arg_tots.push_back(i == 0 ? nArgs : nArgs + arg_tots.back());
127 code <<
"__cppjit_internal::Sep*";
128 size_t offset = (i != 0 ? arg_tots[i - 1] : 0);
129 for (
size_t j = 0; j < nArgs; ++j) {
130 if (i != 0 || j != 0)
139 for (BaseInfos_t::size_type i = 0; i < base_infos.size(); ++i) {
142 code << base_infos[i].bname <<
"(";
143 size_t first = (i != 0 ? arg_tots[i - 1] : 0);
144 for (
size_t j = first; j < arg_tots[i]; ++j) {
149 methods[i].first, j - first)) ==
"&&";
151 code <<
"std::move(";
186 std::ostringstream& err) {
190 if (!PyTuple_Check(bases) || !PyTuple_GET_SIZE(bases) || !dct ||
191 !PyDict_Check(dct)) {
192 err <<
"internal error: expected tuple of bases and proper dictionary";
196 if (!Utility::IncludePython()) {
197 err <<
"failed to include Python.h";
202 const Py_ssize_t nBases = PyTuple_GET_SIZE(bases);
203 BaseInfos_t base_infos;
204 base_infos.reserve(nBases);
205 for (Py_ssize_t ibase = 0; ibase < nBases; ++ibase) {
210 ((
CPPScope*)PyTuple_GET_ITEM(bases, ibase))->fCppType;
213 err <<
"base class is incomplete";
225 PyExc_RuntimeWarning,
226 (
char*)(
"class \"" + bname +
"\" has no virtual destructor")
232 base_infos.emplace_back(
238 bool isDeepHierarchy =
244 static int counter = 0;
245 std::ostringstream osname;
246 osname <<
"Dispatcher" << ++counter;
247 const std::string& derivedName = osname.str();
250 std::ostringstream code;
253 code <<
"namespace __cppjit_internal {\n"
254 <<
"class " << derivedName <<
" : ";
255 for (BaseInfos_t::size_type ibase = 0; ibase < base_infos.size(); ++ibase) {
258 code <<
"public ::" << base_infos[ibase].bname_scoped;
261 if (!isDeepHierarchy)
262 code <<
"protected:\n cppjit::cpyrt::DispatchPtr _internal_self;\n";
270 if (PyMapping_HasKeyString(dct, (
char*)
"__destruct__")) {
271 code <<
" virtual ~" << derivedName
273 " cppjit::cpyrt::PythonGILRAII python_gil_raii;\n"
274 " PyObject* iself = (PyObject*)_internal_self;\n"
275 " if (!iself || iself == Py_None)\n"
277 " Py_INCREF(iself);\n"
278 " PyObject* mtPyName = PyUnicode_FromString(\"__destruct__\");\n"
279 " PyObject* pyresult = PyObject_CallMethodObjArgs(iself, "
281 " Py_DECREF(mtPyName);\n Py_DECREF(iself);\n";
285 code <<
" if (!pyresult) PyErr_Print();\n"
286 " else { Py_DECREF(pyresult); }\n"
289 code <<
" virtual ~" << derivedName <<
"() {}\n";
294 PyObject* items = PyDict_Items(dct);
295 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(items); ++i) {
296 PyObject*
value = PyTuple_GET_ITEM(PyList_GET_ITEM(items, i), 1);
297 if (PyCallable_Check(
value))
298 PyDict_SetItem(clbs, PyTuple_GET_ITEM(PyList_GET_ITEM(items, i), 0),
302 if (PyDict_DelItem(clbs, PyStrings::gInit) != 0)
307 std::set<std::string> protected_names;
311 int has_default = 0, has_cctor = 0, has_ctors = 0, has_tmpl_ctors = 0;
312 AllCtors_t ctors{base_infos.size()};
313 for (BaseInfos_t::size_type ibase = 0; ibase < base_infos.size(); ++ibase) {
314 const auto& binfo = base_infos[ibase];
316 std::vector<interop::TCppMethod_t> methods;
318 bool cctor_found =
false, default_found =
false, any_ctor_found =
false;
319 for (
auto& method : methods) {
321 any_ctor_found =
true;
327 default_found =
true;
328 else if (!cctor_found && nreq == 1) {
329 const std::string& argtype =
331 if (TypeManip::compound(argtype) ==
"&" &&
332 TypeManip::clean_type(argtype,
false) == binfo.bname_scoped)
335 ctors[ibase].push_back(method);
340 std::string mtCppName =
342 PyObject* key = PyUnicode_FromString(mtCppName.c_str());
343 int contains = PyDict_Contains(dct, key);
353 protected_names.insert(mtCppName);
367 code <<
"{\n return " << binfo.bname <<
"::" << mtCppName <<
"(";
373 code <<
"std::move(arg" << i <<
")";
385 if (PyDict_DelItem(clbs, key) != 0)
392 if (base_infos.size() == 1) {
393 std::vector<interop::TCppMethod_t> templ_methods;
395 for (
auto& method : templ_methods) {
397 any_ctor_found =
true;
405 if (cctor_found || (!cctor_found && !any_ctor_found))
407 if (default_found || (!default_found && !any_ctor_found))
409 if (any_ctor_found && !has_tmpl_ctors)
414 for (
const auto& binfo : base_infos) {
415 if (PyDict_Size(clbs)) {
417 for (
size_t ibase = 0; ibase < nbases; ++ibase) {
422 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(keys); ++i) {
425 PyObject* key = PyList_GET_ITEM(keys, i);
426 std::string mtCppName = PyUnicode_AsUTF8(key);
427 const auto& methods = FindBaseMethod(tbase, mtCppName);
428 for (
auto method : methods)
430 if (!methods.empty()) {
431 if (PyDict_DelItem(clbs, key) != 0)
449 if (1 < nBases && (!has_ctors || has_default == nBases))
450 code <<
" " << derivedName <<
"() {}\n";
451 if (has_cctor == nBases) {
452 code <<
" " << derivedName <<
"(const " << derivedName <<
"& other) : ";
453 for (BaseInfos_t::size_type ibase = 0; ibase < base_infos.size(); ++ibase) {
456 code << base_infos[ibase].bname <<
"(other)";
458 if (!isDeepHierarchy)
459 code <<
", _internal_self(other._internal_self, this)";
462 if (has_tmpl_ctors && base_infos.size() == 1) {
465 code <<
" template<typename ...Args>\n " << derivedName
466 <<
"(Args... args) : " << base_infos[0].bname <<
"(args...) {}\n";
472 bool setPublic =
false;
473 for (
const auto& binfo : base_infos) {
474 std::vector<interop::TCppScope_t> datamems;
476 for (
auto data : datamems) {
479 if (dm_name !=
"_internal_self") {
481 protected_names.insert(dname);
486 code <<
" using " << binfo.bname <<
"::" << dname <<
";\n";
493 BaseInfos_t::size_type disp_inited = 0;
494 code <<
"public:\n static void _init_dispatchptr(" << derivedName
495 <<
"* inst, PyObject* self) {\n";
496 if (1 < base_infos.size()) {
497 for (
const auto& binfo : base_infos) {
499 code <<
" " << binfo.bname <<
"::_init_dispatchptr(inst, self);\n";
510 if (disp_inited != base_infos.size())
511 code <<
" new ((void*)&inst->_internal_self) "
512 "cppjit::cpyrt::DispatchPtr{self, true};\n";
517 code <<
"\n static PyObject* _get_dispatch(" << derivedName
519 " cppjit::cpyrt::PythonGILRAII python_gil_raii;\n"
520 " PyObject* res = (PyObject*)inst->_internal_self;\n"
521 " Py_XINCREF(res); return res;\n }";
528 err <<
"failed to compile the dispatcher code";
537 err <<
"failed to retrieve the internal dispatcher";
545 unsigned int flags = (
unsigned int)(klass->
fFlags & CPPScope::kIsMultiCross);
548 ((
CPPScope*)disp_proxy)->fFlags |= CPPScope::kIsMultiCross;
549 ((
CPPScope*)disp_proxy)->fFlags |= CPPScope::kIsPython;
554 for (
const auto&
name : protected_names) {
555 PyObject* disp_dct = PyObject_GetAttr(disp_proxy, PyStrings::gDict);
556#if PY_VERSION_HEX < 0x30d00f0
557 PyObject* pyf = PyMapping_GetItemString(disp_dct, (
char*)
name.c_str());
560 PyMapping_GetOptionalItemString(disp_dct, (
char*)
name.c_str(), &pyf);
563 PyObject_SetAttrString((
PyObject*)klass, (
char*)
name.c_str(), pyf);
569 Py_XDECREF(disp_proxy);