Skip to content

Commit 752117e

Browse files
Improve operator resolution (#129)
* Improve operator resolution `GetMethodTemplate` now also checks for operators methods using `GetClassOperators` `GetGlobalOperator` can now handle templated types * Apply suggestions from code review Co-authored-by: Vassil Vassilev <[email protected]> * fix according to CppInterOp#514 --------- Co-authored-by: Vassil Vassilev <[email protected]>
1 parent 12d2a8e commit 752117e

File tree

2 files changed

+116
-44
lines changed

2 files changed

+116
-44
lines changed

clingwrapper/src/clingwrapper.cxx

Lines changed: 113 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1484,18 +1484,23 @@ Cppyy::TCppMethod_t Cppyy::GetMethodTemplate(
14841484
std::string pureName;
14851485
std::string explicit_params;
14861486

1487-
if (name.find('<') != std::string::npos) {
1487+
if ((name.find("operator<") != 0) &&
1488+
(name.find('<') != std::string::npos)) {
14881489
pureName = name.substr(0, name.find('<'));
14891490
size_t start = name.find('<');
14901491
size_t end = name.rfind('>');
14911492
explicit_params = name.substr(start + 1, end - start - 1);
1493+
} else {
1494+
pureName = name;
14921495
}
14931496

1494-
else pureName = name;
1495-
14961497
std::vector<Cppyy::TCppMethod_t> unresolved_candidate_methods;
14971498
Cpp::GetClassTemplatedMethods(pureName, scope,
14981499
unresolved_candidate_methods);
1500+
if (unresolved_candidate_methods.empty()) {
1501+
// try operators
1502+
Cppyy::GetClassOperators(scope, pureName, unresolved_candidate_methods);
1503+
}
14991504

15001505
// CPyCppyy assumes that we attempt instantiation here
15011506
std::vector<Cpp::TemplateArgInfo> arg_types;
@@ -1520,32 +1525,70 @@ Cppyy::TCppMethod_t Cppyy::GetMethodTemplate(
15201525

15211526
}
15221527

1523-
//
1524-
// static inline
1525-
// std::string type_remap(const std::string& n1, const std::string& n2)
1526-
// {
1527-
// // Operator lookups of (C++ string, Python str) should succeed for the combos of
1528-
// // string/str, wstring/str, string/unicode and wstring/unicode; since C++ does not have a
1529-
// // operator+(std::string, std::wstring), we'll have to look up the same type and rely on
1530-
// // the converters in CPyCppyy/_cppyy.
1531-
// if (n1 == "str" || n1 == "unicode") {
1532-
// if (n2 == "std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >")
1533-
// return n2; // match like for like
1534-
// return "std::string"; // probably best bet
1535-
// } else if (n1 == "float") {
1536-
// return "double"; // debatable, but probably intended
1537-
// } else if (n1 == "complex") {
1538-
// return "std::complex<double>";
1539-
// }
1540-
// return n1;
1541-
// }
1528+
static inline std::string type_remap(const std::string& n1,
1529+
const std::string& n2) {
1530+
// Operator lookups of (C++ string, Python str) should succeed for the
1531+
// combos of string/str, wstring/str, string/unicode and wstring/unicode;
1532+
// since C++ does not have a operator+(std::string, std::wstring), we'll
1533+
// have to look up the same type and rely on the converters in
1534+
// CPyCppyy/_cppyy.
1535+
if (n1 == "str" || n1 == "unicode") {
1536+
// if (n2 ==
1537+
// "std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>
1538+
// >")
1539+
// return n2; // match like for like
1540+
return "std::string"; // probably best bet
1541+
} else if (n1 == "float") {
1542+
return "double"; // debatable, but probably intended
1543+
} else if (n1 == "complex") {
1544+
return "std::complex<double>";
1545+
}
1546+
return n1;
1547+
}
1548+
1549+
void Cppyy::GetClassOperators(Cppyy::TCppScope_t klass,
1550+
const std::string& opname,
1551+
std::vector<TCppScope_t>& operators) {
1552+
if (opname == "operator+")
1553+
Cpp::GetOperator(klass, Cpp::Operator::OP_Plus, operators);
1554+
else if (opname == "operator-")
1555+
Cpp::GetOperator(klass, Cpp::Operator::OP_Minus, operators);
1556+
else if (opname == "operator*")
1557+
Cpp::GetOperator(klass, Cpp::Operator::OP_Star, operators);
1558+
else if (opname == "operator/")
1559+
Cpp::GetOperator(klass, Cpp::Operator::OP_Slash, operators);
1560+
else if (opname == "operator<")
1561+
Cpp::GetOperator(klass, Cpp::Operator::OP_Less, operators);
1562+
else if (opname == "operator<=")
1563+
Cpp::GetOperator(klass, Cpp::Operator::OP_LessEqual, operators);
1564+
else if (opname == "operator>")
1565+
Cpp::GetOperator(klass, Cpp::Operator::OP_Greater, operators);
1566+
else if (opname == "operator>=")
1567+
Cpp::GetOperator(klass, Cpp::Operator::OP_GreaterEqual, operators);
1568+
// FIXME: enabling `==` and `!=` requires friend operators
1569+
// else if (opname == "operator==")
1570+
// Cpp::GetOperator(klass, Cpp::Operator::OP_EqualEqual, operators);
1571+
// else if (opname == "operator!=")
1572+
// Cpp::GetOperator(klass, Cpp::Operator::OP_ExclaimEqual, operators);
1573+
else if (opname == "operator<<")
1574+
Cpp::GetOperator(klass, Cpp::Operator::OP_LessLess, operators);
1575+
else if (opname == "operator>>")
1576+
Cpp::GetOperator(klass, Cpp::Operator::OP_GreaterGreater, operators);
1577+
else if (opname == "operator&")
1578+
Cpp::GetOperator(klass, Cpp::Operator::OP_Amp, operators);
1579+
else if (opname == "operator|")
1580+
Cpp::GetOperator(klass, Cpp::Operator::OP_Pipe, operators);
1581+
}
15421582

15431583
Cppyy::TCppMethod_t Cppyy::GetGlobalOperator(
15441584
TCppType_t scope, const std::string& lc, const std::string& rc, const std::string& opname)
15451585
{
1546-
if ((lc.find('<') != std::string::npos) || (rc.find('<') != std::string::npos)) {
1547-
// arguments of templated types
1548-
return nullptr;
1586+
std::string rc_type = type_remap(rc, lc);
1587+
std::string lc_type = type_remap(lc, rc);
1588+
bool is_templated = false;
1589+
if ((lc_type.find('<') != std::string::npos) ||
1590+
(rc_type.find('<') != std::string::npos)) {
1591+
is_templated = true;
15491592
}
15501593

15511594
std::vector<TCppScope_t> overloads;
@@ -1565,10 +1608,11 @@ Cppyy::TCppMethod_t Cppyy::GetGlobalOperator(
15651608
Cpp::GetOperator(scope, Cpp::Operator::OP_Greater, overloads);
15661609
else if (opname == ">=")
15671610
Cpp::GetOperator(scope, Cpp::Operator::OP_GreaterEqual, overloads);
1568-
else if (opname == "==")
1569-
Cpp::GetOperator(scope, Cpp::Operator::OP_EqualEqual, overloads);
1570-
else if (opname == "!=")
1571-
Cpp::GetOperator(scope, Cpp::Operator::OP_ExclaimEqual, overloads);
1611+
// FIXME: enabling `==` and `!=` requires friend operators
1612+
// else if (opname == "==")
1613+
// Cpp::GetOperator(scope, Cpp::Operator::OP_EqualEqual, overloads);
1614+
// else if (opname == "!=")
1615+
// Cpp::GetOperator(scope, Cpp::Operator::OP_ExclaimEqual, overloads);
15721616
else if (opname == "<<")
15731617
Cpp::GetOperator(scope, Cpp::Operator::OP_LessLess, overloads);
15741618
else if (opname == ">>")
@@ -1578,25 +1622,51 @@ Cppyy::TCppMethod_t Cppyy::GetGlobalOperator(
15781622
else if (opname == "|")
15791623
Cpp::GetOperator(scope, Cpp::Operator::OP_Pipe, overloads);
15801624

1625+
std::vector<Cppyy::TCppMethod_t> unresolved_candidate_methods;
15811626
for (auto overload: overloads) {
1582-
if (Cpp::IsTemplatedFunction(overload))
1627+
if (Cpp::IsTemplatedFunction(overload)) {
1628+
unresolved_candidate_methods.push_back(overload);
15831629
continue;
1584-
1585-
TCppType_t lhs_type = Cpp::GetFunctionArgType(overload, 0);
1586-
if (lc != Cpp::GetTypeAsString(Cpp::GetUnderlyingType(lhs_type)))
1587-
continue;
1588-
1589-
if ((!rc.empty()) && (Cpp::GetFunctionNumArgs(overload) == 2)) {
1590-
TCppType_t rhs_type = Cpp::GetFunctionArgType(overload, 1);
1591-
if (rc != Cpp::GetTypeAsString(Cpp::GetUnderlyingType(rhs_type)))
1592-
continue;
15931630
} else {
1594-
continue;
1595-
}
1631+
TCppType_t lhs_type = Cpp::GetFunctionArgType(overload, 0);
1632+
if (lc_type !=
1633+
Cpp::GetTypeAsString(Cpp::GetUnderlyingType(lhs_type)))
1634+
continue;
15961635

1597-
return overload;
1636+
if (!rc_type.empty()) {
1637+
if (Cpp::GetFunctionNumArgs(overload) != 2)
1638+
continue;
1639+
TCppType_t rhs_type = Cpp::GetFunctionArgType(overload, 1);
1640+
if (rc_type !=
1641+
Cpp::GetTypeAsString(Cpp::GetUnderlyingType(rhs_type)))
1642+
continue;
1643+
}
1644+
return overload;
1645+
}
1646+
}
1647+
if (is_templated) {
1648+
std::string lc_template = lc_type.substr(
1649+
lc_type.find("<") + 1, lc_type.rfind(">") - lc_type.find("<") - 1);
1650+
std::string rc_template = rc_type.substr(
1651+
rc_type.find("<") + 1, rc_type.rfind(">") - rc_type.find("<") - 1);
1652+
1653+
std::vector<Cpp::TemplateArgInfo> arg_types;
1654+
if (auto l = Cppyy::GetType(lc_type, true))
1655+
arg_types.emplace_back(l);
1656+
else
1657+
return nullptr;
1658+
1659+
if (!rc_type.empty()) {
1660+
if (auto r = Cppyy::GetType(rc_type, true))
1661+
arg_types.emplace_back(r);
1662+
else
1663+
return nullptr;
1664+
}
1665+
Cppyy::TCppMethod_t cppmeth = Cpp::BestOverloadFunctionMatch(
1666+
unresolved_candidate_methods, {}, arg_types);
1667+
if (cppmeth)
1668+
return cppmeth;
15981669
}
1599-
16001670
return nullptr;
16011671
}
16021672

clingwrapper/src/cpp_cppyy.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,9 @@ namespace Cppyy {
314314
RPY_EXPORTED
315315
TCppMethod_t GetMethodTemplate(
316316
TCppScope_t scope, const std::string& name, const std::string& proto);
317-
317+
RPY_EXPORTED
318+
void GetClassOperators(Cppyy::TCppScope_t klass, const std::string& opname,
319+
std::vector<TCppScope_t>& operators);
318320
RPY_EXPORTED
319321
TCppMethod_t GetGlobalOperator(
320322
TCppType_t scope, const std::string& lc, const std::string& rc, const std::string& op);

0 commit comments

Comments
 (0)