template<> int scoreArg<QByteArray>(SEXP arg, const SmokeType &type) { if (TYPEOF(arg) == STRSXP) return type.isPtr() ? 1 : 2; else if (TYPEOF(arg) == RAWSXP) return type.isPtr() ? 2 : 3; else return scoreArg_basetype(arg, type); }
template<> int scoreArg<unsigned char>(SEXP arg, const SmokeType &type) { int score = 0; // we consider ptr as array of bytes, and Qt will not copy, but R might free if (!type.isPtr()) { switch(TYPEOF(arg)) { case RAWSXP: score = 3; break; case INTSXP: case REALSXP: score = 1; break; default: break; } } return score; }
template<> int scoreArg<QString>(SEXP arg, const SmokeType &type) { if (TYPEOF(arg) == STRSXP) return type.isPtr() ? 1 : 3; else return 0; }
/* C++ compilers select overloaded methods by ranking each argument in terms of its implicit conversions. There are three different types of implicit conversions: standard, user and ellipsis. We only consider the former, as the others probably are not relevant for Qt. Within standard conversions, there are three ranks: exact, promotion and conversion. We assign these scores 3, 2 and 1, respectively, while 0 indicates no conversion and -1 indicates an error (e.g. unsupported type). The method with better or same ranks for all of its parameters is selected. If there is a tie for the best method, there is an error (in our code). */ int scoreArg_basetype(SEXP arg, const SmokeType &type) { int score = 0; SEXP value = arg; int rtype = TYPEOF(value); unsigned short elem = type.elem(); switch(rtype) { // try the simple cases first case RAWSXP: switch(elem) { case Smoke::t_uchar: score = 3; break; case Smoke::t_short: case Smoke::t_ushort: score = 2; break; case Smoke::t_int: case Smoke::t_uint: case Smoke::t_long: case Smoke::t_ulong: case Smoke::t_float: case Smoke::t_double: score = 1; break; default: break; } break; case INTSXP: switch(elem) { case Smoke::t_enum: if (inherits(value, "QtEnum")) score = 2; else score = 1; break; case Smoke::t_int: score = 3; break; case Smoke::t_uint: if (inherits(value, "QtEnum")) { score = 3; // favor QFlags over enums break; } case Smoke::t_long: case Smoke::t_ulong: case Smoke::t_float: case Smoke::t_double: score = 2; break; case Smoke::t_short: case Smoke::t_ushort: case Smoke::t_uchar: score = 1; break; default: break; } break; case REALSXP: switch(elem) { case Smoke::t_double: score = 3; break; case Smoke::t_float: case Smoke::t_uint: // to distinguish int/uint score = 2; break; case Smoke::t_int: case Smoke::t_long: case Smoke::t_ulong: case Smoke::t_short: case Smoke::t_ushort: case Smoke::t_uchar: case Smoke::t_enum: score = 1; break; default: break; } break; case STRSXP: if (elem == Smoke::t_char && strlen(CHAR(asChar(value))) == 1) score = 2; break; case ENVSXP: if (elem == Smoke::t_class) { SmokeObject *o = SmokeObject::fromSexp(value); if (o) { const char *smokeClass = type.className(); if (o->className() == smokeClass) score = 3; else if (o->instanceOf(smokeClass)) score = 2; /* Not clear if we want to support this C++ feature else { Method *m = Class::fromSmokeType(type)->findImplicitConverter(o); if (m) { score = 1; delete m; } } */ } } break; case NILSXP: if (type.isPtr()) score = 1; break; default: break; } return score; }