Rewrite does_parm_match used in template partial specialization

Re-implement this function in preparation for fixing bugs in this
function. This rewrite should result in no change in the way it
previously worked for now.
This commit is contained in:
William S Fulton 2023-01-12 08:38:17 +00:00
commit cac16bf94d
2 changed files with 37 additions and 43 deletions

View file

@ -130,9 +130,6 @@ namespace AA { // thinks X is in AA namespace
namespace Space { namespace Space {
} }
template<typename T> struct Vector { template<typename T> struct Vector {
#ifdef SWIG
%template() Space::VectorHelper<T>;
#endif
void gook(T i) {} void gook(T i) {}
void geeko(double d) {} void geeko(double d) {}
void geeky(int d) {} void geeky(int d) {}
@ -142,7 +139,6 @@ template<typename T> struct Vector<T *> {
}; };
*/ */
//} //}
%}
%template(VectorIntPtr) Space::Vector<int *>; // should fail as Vector is in global namespace %template(VectorIntPtr) Space::Vector<int *>; // should fail as Vector is in global namespace
// is this a regression - no fails in 1.3.40 too // is this a regression - no fails in 1.3.40 too

View file

@ -630,57 +630,53 @@ typedef enum { ExactNoMatch = -2, PartiallySpecializedNoMatch = -1, PartiallySpe
* template parameter type. Typedef reduce 'partial_parm_type' to see if it matches 'type'. * template parameter type. Typedef reduce 'partial_parm_type' to see if it matches 'type'.
* *
* type - template parameter type to match against * type - template parameter type to match against
* partial_parm_type - partially specialized template type - a possible match * partial_parm_type - specialized template type, for example, r.$1 (partially specialized) or r.int (fully specialized)
* partial_parm_type_base - base type of partial_parm_type * partial_parm - partially specialized template parameter name, such as, $1 or $2 or $3, etc
* tscope - template scope * tscope - template scope
* specialization_priority - (output) contains a value indicating how good the match is * specialization_priority - (output) contains a value indicating how good the match is
* (higher is better) only set if return is set to PartiallySpecializedMatch or ExactMatch. * (higher is better) only set if return is set to PartiallySpecializedMatch or ExactMatch.
* ----------------------------------------------------------------------------- */ * ----------------------------------------------------------------------------- */
static EMatch does_parm_match(SwigType *type, SwigType *partial_parm_type, const char *partial_parm_type_base, Symtab *tscope, int *specialization_priority) { static EMatch does_parm_match(SwigType *type, SwigType *partial_parm_type, const char *partial_parm, Symtab *tscope, int *specialization_priority) {
static const int EXACT_MATCH_PRIORITY = 99999; /* a number bigger than the length of any conceivable type */ static const int EXACT_MATCH_PRIORITY = 99999; /* a number bigger than the length of any conceivable type */
int matches;
int substitutions;
EMatch match;
SwigType *ty = Swig_symbol_typedef_reduce(type, tscope); SwigType *ty = Swig_symbol_typedef_reduce(type, tscope);
String *base = SwigType_base(ty); SwigType *pp_prefix = SwigType_prefix(partial_parm_type);
SwigType *t = Copy(partial_parm_type); int pp_len = Len(pp_prefix);
substitutions = Replaceid(t, partial_parm_type_base, base); /* eg: Replaceid("p.$1", "$1", "int") returns t="p.int" */ EMatch match = Strstr(partial_parm_type, partial_parm) == 0 ? ExactNoMatch : PartiallySpecializedNoMatch;
matches = Equal(ty, t);
*specialization_priority = -1; *specialization_priority = -1;
if (substitutions == 1) {
/* we have a non-explicit specialized parameter (in partial_parm_type) because a substitution for $1, $2... etc has taken place */
SwigType *tt = Copy(partial_parm_type);
int len;
/*
check for match to partial specialization type, for example, all of the following could match the type in the %template:
template <typename T> struct XX {};
template <typename T> struct XX<T &> {}; // r.$1
template <typename T> struct XX<T const&> {}; // r.q(const).$1
template <typename T> struct XX<T *const&> {}; // r.q(const).p.$1
%template(XXX) XX<int *const&>; // r.q(const).p.int
where type="r.q(const).p.int" will match either of tt="r.", tt="r.q(const)" tt="r.q(const).p" if (Equal(ty, partial_parm_type)) {
*/ match = ExactMatch;
Replaceid(tt, partial_parm_type_base, ""); /* remove the $1, $2 etc, eg tt="p.$1" => "p." */ *specialization_priority = EXACT_MATCH_PRIORITY; /* exact matches always take precedence */
len = Len(tt); } else if (match == PartiallySpecializedNoMatch) {
if (Strncmp(tt, ty, len) == 0) { if ((pp_len > 0 && Strncmp(ty, pp_prefix, pp_len) == 0)) {
/*
type starts with pp_prefix, so it is a partial specialization type match, for example,
all of the following could match the type in the %template:
template <typename T> struct XX {};
template <typename T> struct XX<T &> {}; // r.$1
template <typename T> struct XX<T const&> {}; // r.q(const).$1
template <typename T> struct XX<T *const&> {}; // r.q(const).p.$1
%template(XXX) XX<int *const&>; // r.q(const).p.int
where type="r.q(const).p.int" will match either of pp_prefix="r.", pp_prefix="r.q(const)." pp_prefix="r.q(const).p."
*/
match = PartiallySpecializedMatch; match = PartiallySpecializedMatch;
*specialization_priority = len; *specialization_priority = pp_len;
} else { } else if (pp_len == 0 && Equal(partial_parm_type, partial_parm)) {
match = PartiallySpecializedNoMatch; /*
type without a prefix match, as in $1 for int
template <typename T, typename U> struct XX {};
template <typename T, typename U> struct XX<T, U &> {}; // $1,r.$2
%template(XXX) XX<int, double&>; // int,r.double
*/
match = PartiallySpecializedMatch;
*specialization_priority = pp_len;
} }
Delete(tt);
} else {
match = matches ? ExactMatch : ExactNoMatch;
if (matches)
*specialization_priority = EXACT_MATCH_PRIORITY; /* exact matches always take precedence */
} }
/* /*
Printf(stdout, " does_parm_match %2d %5d [%s] [%s]\n", match, *specialization_priority, type, partial_parm_type); Printf(stdout, " does_parm_match %2d %5d [%s] [%s]\n", match, *specialization_priority, type, partial_parm_type);
*/ */
Delete(t);
Delete(base);
Delete(ty); Delete(ty);
return match; return match;
} }
@ -721,6 +717,7 @@ static Node *template_locate(String *name, Parm *instantiated_parms, String *sym
templ = Swig_symbol_clookup(name, 0); templ = Swig_symbol_clookup(name, 0);
if (templ) { if (templ) {
/* TODO: check that this is not a specialization (might be a user error specializing a template before a primary template), but note https://stackoverflow.com/questions/9757642/wrapping-specialised-c-template-class-with-swig */
if (template_debug) { if (template_debug) {
Printf(stdout, " found primary template <%s> '%s'\n", ParmList_str_defaultargs(Getattr(templ, "templateparms")), Getattr(templ, "name")); Printf(stdout, " found primary template <%s> '%s'\n", ParmList_str_defaultargs(Getattr(templ, "templateparms")), Getattr(templ, "name"));
} }
@ -902,9 +899,10 @@ static Node *template_locate(String *name, Parm *instantiated_parms, String *sym
* T * T
* *
* An ambiguous example when attempting to match as either specialization could match: %template() X<int *, double *>; * An ambiguous example when attempting to match as either specialization could match: %template() X<int *, double *>;
* template<typename T1, typename T2> X class {}; // primary template * template<typename T1, typename T2> class X {}; // primary template
* template<typename T1> X<T1, double *> class {}; // specialization (1) * template<typename T1> class X<T1, double *> {}; // specialization (1)
* template<typename T2> X<int *, T2> class {}; // specialization (2) * template<typename T2> class X<int *, T2> {}; // specialization (2)
*
*/ */
if (template_debug) { if (template_debug) {
int row, col; int row, col;