Template partial specialization improvements

Closes #1300

Changes to support the first example below (partial specialization of
template parameter types like Vect<int>). Previous implementation and
design could only handle one template parameter name per template
specialization argument, such as Vect<TS> for the first template
specialization argument (for first example below)
  template<class TS, typename TTS> class Foo<Vect<TS>, int> { ... };
and not
  template<class TS, typename TTS> class Foo<Vect<TS, TTS>, int> { ... };
New approach is to not modify 'templateparms' in the template node,
(except to fill in default args from primary template)
Previous implementation also assumed a template parameter could not be
used more than once in the specialized arguments, such as
  template<typename T> struct Hey<T, T> { void specialA() {} };

Examples
========
1) For primary:
  template<class T, typename TT> class Foo { ... };
and specialization:
  template<class TS, typename TTS> class Foo<Vect<TS>, TTS> { ... };

Fix specialization template from (wrong)
| templateparms - 'Vect< TS >,typename TTS'
to (correct/new way)
| templateparms - 'class TS,typename TTS'

2) For primary:
  template<typename P1 = int, typename P2 = double> struct Partialler { void primary(P1, P2) {}; };
and specialization:
  template<typename S1, typename S2> struct Partialler<S2, S1*> { void special(S1*, S2, bool) {}; };

Specialized template changes from (wrong)
| templateparms - 'typename S2=int,typename S1=double'
to (correct/new way, default args are removed)
| templateparms - 'typename S1,typename S2'

and subsequent change to partialargs from
| partialargs  - "Partialler<($1,p.$2)>"
to
| partialargs  - "Partialler<($2,p.$1)>"
so that the $n number is now more logically the nth template parameter in templateparms

3) For primary:
  template<typename X, typename Y> struct Hey { void primary() {} };
and specialization:
  template<typename T> struct Hey<T, T> { void specialA() {} };

old (wrong/old way)
| templateparms - 'typename T,typename T'
new (correct/new way)
| templateparms - 'typename T'

These are unchanged and are okay:
| partialargs  - "Hey<($1,$1)>"

4) For primary:
  enum Hello { hi, hello };
  template <Hello, class A> struct C {};
and specialization:
  template <class A> struct C<hello,A> { ... };

old (wrong/old way)
| templateparms - 'hello,class A'
new (correct/new way)
| templateparms - 'class A'

and subsequent changes to partialargs from
| partialargs  - "C<(hi,$2)>"
to
| partialargs  - "C<(hi,$1)>"

Test-suite
==========
Identical output as before in Python but in Java, an unimportant change
in cpp11_variadic_function_templates.i results in one variadic parameter
name being different.

New testcase template_partial_specialization_more.i with more testcases
added including above examples that are not already in the test-suite.
This commit is contained in:
William S Fulton 2023-01-30 08:22:33 +00:00
commit 817c700ced
6 changed files with 309 additions and 169 deletions

View file

@ -7,6 +7,24 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
Version 4.2.0 (in progress) Version 4.2.0 (in progress)
=========================== ===========================
2023-02-15: wsfulton
#1300 Further partial template specialization fixes.
Fixes when templates are used as a template parameter in a partially specialized
instantiation such as:
template<typename V> struct Vect {};
template<class T, typename TT> class Foo { ... };
template<class TS, typename TTS> class Foo<Vect<TS>, TTS> { ... };
%template(VectInt) Vect<int>;
%template(FooVectIntDouble) Foo<Vect<int>, double>; // was previously attempting to use primary template
Also fixes partial specialization where the same template parameter name is used twice,
for example:
template<typename X, typename Y> struct H { ... };
template<typename T> struct H<T, T> { ... };
%template(HInts) H<int, int>; // was previously attempting to use primary template
2023-01-27: jschueller 2023-01-27: jschueller
#2492 [python] Fix unused parameter warnings for self parameter in #2492 [python] Fix unused parameter warnings for self parameter in
generated C/C++ wrapper code. generated C/C++ wrapper code.

View file

@ -487,6 +487,7 @@ CPP_TEST_CASES += \
template_parameters_global_scope \ template_parameters_global_scope \
template_partial_arg \ template_partial_arg \
template_partial_specialization \ template_partial_specialization \
template_partial_specialization_more \
template_partial_specialization_typedef \ template_partial_specialization_typedef \
template_qualifier \ template_qualifier \
template_ref_type \ template_ref_type \

View file

@ -0,0 +1,103 @@
%module template_partial_specialization_more
// (1) Based on https://stackoverflow.com/questions/9757642/wrapping-specialised-c-template-class-with-swig
%inline %{
template<typename V> struct Vect {};
template<class T, typename TT>
class Foo {
public:
Foo() {}
virtual ~Foo() {}
T primary() const { return T(); }
};
template<class TS, typename TTS>
class Foo<Vect<TS>, TTS> {
public:
Foo() {}
virtual ~Foo() {}
TS partially_specialized(TS parmin) const { return parmin; }
};
template<>
class Foo<Vect<double>, double> {
public:
Foo() {}
virtual ~Foo() {}
double value_fully_specialized(double d) const { return d; }
};
template<class T, typename TT>
class Foo<T*, TT> {
public:
Foo() {}
virtual ~Foo() {}
int pointer_specialize(T myT) const { return 0; }
};
%}
%template(VectInt) Vect<int>;
%template(FooVectIntDouble) Foo<Vect<int>, double>; // was failing
%template(FooShortPtrDouble) Foo<short*, double>;
%template(FooVectVectInt) Foo<Vect<Vect<int>>, int>; // was failing
// (2) Same types in both args
%inline %{
template<typename X, typename Y> struct Hey { void primary() {} };
template<typename T> struct Hey<T, T> { void special_hey() {} };
%}
%template(HeyInts) Hey<int, int>; // was failing, was calling primary
// (3) Partial specialization using one template parameter instead of two
%inline %{
struct PlainStruct {};
template <typename T, typename U> struct XX { void primary() {} };
template <typename T> struct XX<T, T &> { void special1() {} }; // r.$1
template <typename T> struct XX<T, T const&> { void special2() {} }; // r.q(const).$1
template <typename T> struct XX<T, T *const&> { void special3() {} }; // r.q(const).p.$1
%}
%template(XX1) XX<int, int&>; // was failing, was calling primary
%template(XX2) XX<int, int const&>;
%template(XX3) XX<PlainStruct, PlainStruct *const&>;
// (4) Switching parameters around
%inline %{
#include <iostream>
template<typename P1 = int, typename P2 = double> struct Partialler { void primary(P1, P2) {}; };
template<typename S1, typename S2> struct Partialler<S2, S1*> { void special(S1*, S2, bool) {}; };
%}
%template(PartiallerPrimary) Partialler<short, short>;
%template(PartiallerSpecial) Partialler<int, PlainStruct*>;
// (5) Default args used in specialization, like std::list
%inline %{
template <typename A> struct Allocator {};
template <typename T, class Alloc = Allocator<T>> struct Lyst { void primary(T, Allocator<T>) {} };
template <typename TT, class XXAlloc> struct Lyst<TT*, XXAlloc> { void specialized1(TT, XXAlloc) {} };
template <typename TTT, class YY> struct Lyst<TTT**, Allocator<YY>> { void specialized2(TTT, YY) {} };
// TODO Error: Inconsistent argument count in template partial specialization. 1 2
//template <typename TTTT> struct Lyst<const TTTT&> { void specialized3(TTTT) {} };
void test_list() {
int myint = 0;
Lyst<int> lis;
lis.primary(myint, Allocator<int>());
PlainStruct ps;
Lyst<PlainStruct *> liss;
liss.specialized1(ps, Allocator<PlainStruct *>());
double mydouble = 0;
Lyst<double **> lissd;
lissd.specialized2(mydouble, (double **)nullptr);
// Lyst<const int&> lissconstint;
// lissconstint.specialized3(myint);
}
%}
%template(LystDouble) Lyst<double>;
//%template(LystDouble) Lyst<short, Allocator<short>>;
%template(LystPlainStructPtr) Lyst<PlainStruct *>;
%template(LystDoublePtrPtr) Lyst<double **>; // called specialized1 instead of specialized2

View file

@ -68,7 +68,7 @@ extern "C" {
extern int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab *tscope); extern int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab *tscope);
extern Node *Swig_cparse_template_locate(String *name, ParmList *tparms, String *symname, Symtab *tscope); extern Node *Swig_cparse_template_locate(String *name, ParmList *tparms, String *symname, Symtab *tscope);
extern void Swig_cparse_debug_templates(int); extern void Swig_cparse_debug_templates(int);
extern ParmList *Swig_cparse_template_parms_expand(ParmList *instantiated_parameters, Node *primary); extern ParmList *Swig_cparse_template_parms_expand(ParmList *instantiated_parameters, Node *primary, Node *templ);
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -2883,7 +2883,7 @@ template_directive: SWIGTEMPLATE LPAREN idstringopt RPAREN idcolonnt LESSTHAN va
Node *primary_template = Swig_symbol_clookup(tname, 0); Node *primary_template = Swig_symbol_clookup(tname, 0);
/* Expand the template */ /* Expand the template */
ParmList *temparms = Swig_cparse_template_parms_expand($7, primary_template); ParmList *temparms = Swig_cparse_template_parms_expand($7, primary_template, nn);
templnode = copy_node(nn); templnode = copy_node(nn);
update_nested_classes(templnode); /* update classes nested within template */ update_nested_classes(templnode); /* update classes nested within template */
@ -4128,112 +4128,32 @@ cpp_template_decl : TEMPLATE LESSTHAN template_parms GREATERTHAN {
if (!Getattr($$,"sym:weak")) { if (!Getattr($$,"sym:weak")) {
Setattr($$,"sym:typename","1"); Setattr($$,"sym:typename","1");
} }
Setattr($$, "primarytemplate", tempn);
Setattr($$, "templateparms", $3);
Delattr($$, "specialization");
Setattr($$, "partialspecialization", "1");
if (Len(tlist) != ParmList_len(Getattr(tempn,"templateparms"))) { if (Len(tlist) != ParmList_len(Getattr(tempn,"templateparms"))) {
Swig_error(Getfile($$),Getline($$),"Inconsistent argument count in template partial specialization. %d %d\n", Len(tlist), ParmList_len(Getattr(tempn,"templateparms"))); Swig_error(Getfile($$),Getline($$),"Inconsistent argument count in template partial specialization. %d %d\n", Len(tlist), ParmList_len(Getattr(tempn,"templateparms")));
} else { } else {
/* Create a specialized name with template parameters replaced with $ variables, such as, X<(T1,p.T2) => X<($1,p.$2)> */
/* This code builds the argument list for the partial template
specialization. This is a little hairy, but the idea is as
follows:
$3 contains a list of arguments supplied for the template.
For example template<class T>.
tlist is a list of the specialization arguments--which may be
different. For example class<int,T>.
tp is a copy of the arguments in the original template definition.
The patching algorithm walks through the list of supplied
arguments ($3), finds the position in the specialization arguments
(tlist), and then patches the name in the argument list of the
original template.
*/
{
String *pn;
Parm *p, *p1;
int i, nargs;
Parm *tp = CopyParmList(Getattr(tempn,"templateparms"));
nargs = Len(tlist);
p = $3;
while (p) {
for (i = 0; i < nargs; i++){
pn = Getattr(p,"name");
if (Strcmp(pn,SwigType_base(Getitem(tlist,i))) == 0) {
int j;
Parm *p1 = tp;
for (j = 0; j < i; j++) {
p1 = nextSibling(p1);
}
Setattr(p1,"name",pn);
Setattr(p1,"partialarg","1");
}
}
p = nextSibling(p);
}
p1 = tp;
i = 0;
while (p1) {
if (!Getattr(p1,"partialarg")) {
Delattr(p1,"name");
Setattr(p1,"type", Getitem(tlist,i));
}
i++;
p1 = nextSibling(p1);
}
Setattr($$,"templateparms",tp);
Delete(tp);
}
#if 0
/* Patch the parameter list */
if (tempn) {
Parm *p,*p1;
ParmList *tp = CopyParmList(Getattr(tempn,"templateparms"));
p = $3;
p1 = tp;
while (p && p1) {
String *pn = Getattr(p,"name");
Printf(stdout,"pn = '%s'\n", pn);
if (pn) Setattr(p1,"name",pn);
else Delattr(p1,"name");
pn = Getattr(p,"type");
if (pn) Setattr(p1,"type",pn);
p = nextSibling(p);
p1 = nextSibling(p1);
}
Setattr($$,"templateparms",tp);
Delete(tp);
} else {
Setattr($$,"templateparms",$3);
}
#endif
Delattr($$,"specialization");
Setattr($$,"partialspecialization","1");
/* Create a specialized name for matching */
{
Parm *p = $3; Parm *p = $3;
String *fname = NewString(Getattr($$,"name")); String *fname = NewString(Getattr($$,"name"));
String *ffname = 0; String *ffname = 0;
ParmList *partialparms = 0; ParmList *partialparms = 0;
char tmp[32]; char tmp[32];
int i, ilen; int i = 0;
while (p) { while (p) {
String *n = Getattr(p,"name"); String *name = Getattr(p,"name");
if (!n) { ++i;
if (!name) {
p = nextSibling(p); p = nextSibling(p);
continue; continue;
} }
ilen = Len(tlist); sprintf(tmp, "$%d", i);
for (i = 0; i < ilen; i++) { Replaceid(fname, name, tmp);
if (Strstr(Getitem(tlist,i),n)) {
sprintf(tmp,"$%d",i+1);
Replaceid(fname,n,tmp);
}
}
p = nextSibling(p); p = nextSibling(p);
} }
/* Patch argument names with typedef */ /* Patch argument names with typedef */
@ -4279,7 +4199,6 @@ cpp_template_decl : TEMPLATE LESSTHAN template_parms GREATERTHAN {
Setattr($$,"partialargs",ffname); Setattr($$,"partialargs",ffname);
Swig_symbol_cadd(ffname,$$); Swig_symbol_cadd(ffname,$$);
} }
}
Delete(tlist); Delete(tlist);
Delete(targs); Delete(targs);
} else { } else {

View file

@ -13,6 +13,7 @@
#include "swig.h" #include "swig.h"
#include "cparse.h" #include "cparse.h"
#include <ctype.h>
static int template_debug = 0; static int template_debug = 0;
@ -396,25 +397,43 @@ static void cparse_postprocess_expanded_template(Node *n) {
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* partial_arg() * partial_arg()
*
* Return a parameter with type that matches the specialized template argument.
* If the input has no partial type, the name is not set in the returned parameter.
*
* type: an instantiated template parameter type, for example: Vect<(int)>
* partialtype: type from specialized template where parameter name has been
* replaced by a $ variable, for example: Vect<($1)>
*
* Returns a parameter of type 'int' and name $1 for the two example parameters above.
* ----------------------------------------------------------------------------- */ * ----------------------------------------------------------------------------- */
static String *partial_arg(String *s, String *p) { static Parm *partial_arg(const SwigType *type, const SwigType *partialtype) {
char *c; SwigType *parmtype;
char *cp = Char(p); String *parmname = 0;
String *prefix; const char *cp = Char(partialtype);
String *newarg; const char *c = strchr(cp, '$');
/* Find the prefix on the partial argument */ if (c) {
int suffix_length;
c = strchr(cp, '$'); int prefix_length = c - cp;
if (!c) { int type_length = Len(type);
return Copy(s); const char *suffix = c;
String *prefix = NewStringWithSize(cp, prefix_length);
while (++suffix) {
if (!isdigit((int)*suffix))
break;
}
parmname = NewStringWithSize(c, suffix - c); /* $1, $2 etc */
suffix_length = strlen(suffix);
assert(Strstr(type, prefix) == Char(type)); /* check that the start of both types match */
assert(strcmp(Char(type) + type_length - suffix_length, suffix) == 0); /* check that the end of both types match */
parmtype = NewStringWithSize(Char(type) + prefix_length, type_length - suffix_length - prefix_length);
Delete(prefix);
} else {
parmtype = Copy(type);
} }
prefix = NewStringWithSize(cp, (int)(c - cp)); return NewParmWithoutFileLineInfo(parmtype, parmname);
newarg = Copy(s);
Replace(newarg, prefix, "", DOH_REPLACE_FIRST);
Delete(prefix);
return newarg;
} }
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
@ -429,6 +448,8 @@ int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab
String *tbase; String *tbase;
Parm *unexpanded_variadic_parm = 0; Parm *unexpanded_variadic_parm = 0;
ParmList *expanded_variadic_parms = 0; ParmList *expanded_variadic_parms = 0;
ParmList *templateparms = Getattr(n, "templateparms");
ParmList *templateparmsraw = 0;
patchlist = NewList(); /* List of String * ("name" and "value" attributes) */ patchlist = NewList(); /* List of String * ("name" and "value" attributes) */
cpatchlist = NewList(); /* List of String * (code) */ cpatchlist = NewList(); /* List of String * (code) */
typelist = NewList(); /* List of SwigType * types */ typelist = NewList(); /* List of SwigType * types */
@ -439,12 +460,13 @@ int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab
tname = Copy(Getattr(n, "name")); tname = Copy(Getattr(n, "name"));
tbase = Swig_scopename_last(tname); tbase = Swig_scopename_last(tname);
/* Look for partial specialization matching */
if (Getattr(n, "partialargs")) { if (Getattr(n, "partialargs")) {
/* Partial specialization */
Parm *p, *tp; Parm *p, *tp;
ParmList *ptargs = SwigType_function_parms(Getattr(n, "partialargs"), n); ParmList *ptargs = SwigType_function_parms(Getattr(n, "partialargs"), n);
p = ptargs; p = ptargs;
tp = tparms; tp = tparms;
/* Adjust templateparms so that the type is expanded, eg typename => int */
while (p && tp) { while (p && tp) {
SwigType *ptype; SwigType *ptype;
SwigType *tptype; SwigType *tptype;
@ -453,9 +475,20 @@ int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab
tptype = Getattr(tp, "type"); tptype = Getattr(tp, "type");
if (ptype && tptype) { if (ptype && tptype) {
SwigType *ty = Swig_symbol_typedef_reduce(tptype, tscope); SwigType *ty = Swig_symbol_typedef_reduce(tptype, tscope);
partial_type = partial_arg(ty, ptype); Parm *partial_parm = partial_arg(ty, ptype);
String *partial_name = Getattr(partial_parm, "name");
partial_type = Copy(Getattr(partial_parm, "type"));
/* Printf(stdout,"partial '%s' '%s' ---> '%s'\n", tptype, ptype, partial_type); */ /* Printf(stdout,"partial '%s' '%s' ---> '%s'\n", tptype, ptype, partial_type); */
Setattr(tp, "type", partial_type); if (partial_name && strchr(Char(partial_name), '$') == Char(partial_name)) {
int index = atoi(Char(partial_name) + 1) - 1;
assert(index >= 0);
Parm *parm = ParmList_nth_parm(templateparms, index);
assert(parm);
if (parm) {
Setattr(parm, "type", partial_type);
}
}
Delete(partial_parm);
Delete(partial_type); Delete(partial_type);
Delete(ty); Delete(ty);
} }
@ -464,20 +497,17 @@ int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab
} }
assert(ParmList_len(ptargs) == ParmList_len(tparms)); assert(ParmList_len(ptargs) == ParmList_len(tparms));
Delete(ptargs); Delete(ptargs);
} else {
Setattr(n, "templateparmsraw", Getattr(n, "templateparms"));
templateparms = CopyParmList(tparms);
Setattr(n, "templateparms", templateparms);
} }
/* /* TODO: variadic parms for partially specialized templates */
Parm *p = tparms; templateparmsraw = Getattr(n, "templateparmsraw");
while (p) { unexpanded_variadic_parm = ParmList_variadic_parm(templateparmsraw);
Printf(stdout, "tparm: '%s' '%s' '%s'\n", Getattr(p, "name"), Getattr(p, "type"), Getattr(p, "value"));
p = nextSibling(p);
}
*/
ParmList *templateparms = Getattr(n, "templateparms");
unexpanded_variadic_parm = ParmList_variadic_parm(templateparms);
if (unexpanded_variadic_parm) if (unexpanded_variadic_parm)
expanded_variadic_parms = ParmList_nth_parm(tparms, ParmList_len(templateparms) - 1); expanded_variadic_parms = ParmList_nth_parm(templateparms, ParmList_len(templateparmsraw) - 1);
/* Printf(stdout,"targs = '%s'\n", templateargs); /* Printf(stdout,"targs = '%s'\n", templateargs);
Printf(stdout,"rname = '%s'\n", rname); Printf(stdout,"rname = '%s'\n", rname);
@ -496,24 +526,23 @@ int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab
/* Patch all of the types */ /* Patch all of the types */
{ {
Parm *tp = Getattr(n, "templateparms"); Parm *tp = Getattr(n, "templateparms");
Parm *p = tparms;
/* Printf(stdout,"%s\n", ParmList_str_defaultargs(tp)); */ /* Printf(stdout,"%s\n", ParmList_str_defaultargs(tp)); */
if (p && tp) { if (tp) {
Symtab *tsdecl = Getattr(n, "sym:symtab"); Symtab *tsdecl = Getattr(n, "sym:symtab");
String *tsname = Getattr(n, "sym:name"); String *tsname = Getattr(n, "sym:name");
while (p && tp) { while (tp) {
String *name, *value, *valuestr, *tmp, *tmpr; String *name, *value, *valuestr, *tmp, *tmpr;
int sz, i; int sz, i;
String *dvalue = 0; String *dvalue = 0;
String *qvalue = 0; String *qvalue = 0;
name = Getattr(tp, "name"); name = Getattr(tp, "name");
value = Getattr(p, "value"); value = Getattr(tp, "value");
if (name) { if (name) {
if (!value) if (!value)
value = Getattr(p, "type"); value = Getattr(tp, "type");
qvalue = Swig_symbol_typedef_reduce(value, tsdecl); qvalue = Swig_symbol_typedef_reduce(value, tsdecl);
dvalue = Swig_symbol_type_qualify(qvalue, tsdecl); dvalue = Swig_symbol_type_qualify(qvalue, tsdecl);
if (SwigType_istemplate(dvalue)) { if (SwigType_istemplate(dvalue)) {
@ -524,17 +553,6 @@ int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab
assert(dvalue); assert(dvalue);
valuestr = SwigType_str(dvalue, 0); valuestr = SwigType_str(dvalue, 0);
/* Need to patch default arguments */
{
Parm *rp = nextSibling(p);
while (rp) {
String *rvalue = Getattr(rp, "value");
if (rvalue) {
Replace(rvalue, name, dvalue, DOH_REPLACE_ID);
}
rp = nextSibling(rp);
}
}
sz = Len(patchlist); sz = Len(patchlist);
for (i = 0; i < sz; i++) { for (i = 0; i < sz; i++) {
String *s = Getitem(patchlist, i); String *s = Getitem(patchlist, i);
@ -580,10 +598,7 @@ int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab
Delete(dvalue); Delete(dvalue);
Delete(qvalue); Delete(qvalue);
} }
p = nextSibling(p);
tp = nextSibling(tp); tp = nextSibling(tp);
if (!p)
p = tp;
} }
} else { } else {
/* No template parameters at all. This could be a specialization */ /* No template parameters at all. This could be a specialization */
@ -625,26 +640,47 @@ int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab
typedef enum { ExactNoMatch = -2, PartiallySpecializedNoMatch = -1, PartiallySpecializedMatch = 1, ExactMatch = 2 } EMatch; typedef enum { ExactNoMatch = -2, PartiallySpecializedNoMatch = -1, PartiallySpecializedMatch = 1, ExactMatch = 2 } EMatch;
/* -----------------------------------------------------------------------------
* is_exact_partial_type()
*
* Return 1 if parm matches $1, $2, $3 etc exactly without any other prefixes or
* suffixes. Return 0 otherwise.
* ----------------------------------------------------------------------------- */
static int is_exact_partial_type(const SwigType *type) {
const char *c = Char(type);
int is_exact = 0;
if (*c == '$' && isdigit((int)*(c + 1))) {
const char *suffix = c + 1;
while (++suffix) {
if (!isdigit((int)*suffix))
break;
}
is_exact = (*suffix == 0);
}
return is_exact;
}
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* does_parm_match() * does_parm_match()
* *
* Template argument deduction - check if a template type matches a partially specialized * Template argument deduction - check if a template type matches a partially specialized
* 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 - specialized template type, for example, r.$1 (partially specialized) or r.int (fully specialized) * partial_parm_type - specialized template type, for example, r.$1 (partially specialized) or r.int (fully specialized)
* 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, Symtab *tscope, int *specialization_priority) { static EMatch does_parm_match(SwigType *type, SwigType *partial_parm_type, 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 */
static const int TEMPLATE_MATCH_PRIORITY = 1000; /* a priority added for each nested template, assumes max length of any prefix, such as r.q(const). , is less than this number */
SwigType *ty = Swig_symbol_typedef_reduce(type, tscope); SwigType *ty = Swig_symbol_typedef_reduce(type, tscope);
SwigType *pp_prefix = SwigType_prefix(partial_parm_type); SwigType *pp_prefix = SwigType_prefix(partial_parm_type);
int pp_len = Len(pp_prefix); int pp_len = Len(pp_prefix);
EMatch match = Strstr(partial_parm_type, partial_parm) == 0 ? ExactNoMatch : PartiallySpecializedNoMatch; EMatch match = Strchr(partial_parm_type, '$') == 0 ? ExactNoMatch : PartiallySpecializedNoMatch;
*specialization_priority = -1; *specialization_priority = -1;
if (Equal(ty, partial_parm_type)) { if (Equal(ty, partial_parm_type)) {
@ -653,27 +689,89 @@ static EMatch does_parm_match(SwigType *type, SwigType *partial_parm_type, const
} else if (match == PartiallySpecializedNoMatch) { } else if (match == PartiallySpecializedNoMatch) {
if ((pp_len > 0 && Strncmp(ty, pp_prefix, pp_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, 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: all of the following could match the type in the %template:
template <typename T> struct XX {}; template <typename T> struct XX {};
template <typename T> struct XX<T &> {}; // r.$1 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).$1
template <typename T> struct XX<T *const&> {}; // r.q(const).p.$1 template <typename T> struct XX<T *const&> {}; // r.q(const).p.$1
%template(XXX) XX<int *const&>; // r.q(const).p.int %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." 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 = pp_len; *specialization_priority = pp_len;
} else if (pp_len == 0 && Equal(partial_parm_type, partial_parm)) { } else if (pp_len == 0 && is_exact_partial_type(partial_parm_type)) {
/* /*
type without a prefix match, as in $1 for int Type without a prefix match, as in $1 for int
template <typename T, typename U> struct XX {}; template <typename T, typename U> struct XX {};
template <typename T, typename U> struct XX<T, U &> {}; // $1,r.$2 template <typename T, typename U> struct XX<T, U &> {}; // $1,r.$2
%template(XXX) XX<int, double&>; // int,r.double %template(XXX) XX<int, double&>; // int,r.double
*/ */
match = PartiallySpecializedMatch; match = PartiallySpecializedMatch;
*specialization_priority = pp_len; *specialization_priority = pp_len;
} else {
/*
Check for template types that are templates such as
template<typename V> struct Vect {};
template<typename T> class XX {};
template<class TT> class XX<Vect<TT>> {};
%template(XXVectInt) XX<Vect<int>>;
matches type="Vect<(int)>" and partial_parm_type="Vect<($1)>"
*/
if (SwigType_istemplate(partial_parm_type) && SwigType_istemplate(ty)) {
SwigType *qt = Swig_symbol_typedef_reduce(ty, tscope);
String *tsuffix = SwigType_templatesuffix(qt);
SwigType *pp_qt = Swig_symbol_typedef_reduce(partial_parm_type, tscope);
String *pp_tsuffix = SwigType_templatesuffix(pp_qt);
if (Equal(tsuffix, pp_tsuffix) && Len(tsuffix) == 0) {
String *tprefix = SwigType_templateprefix(qt);
String *qprefix = SwigType_typedef_qualified(tprefix);
String *pp_tprefix = SwigType_templateprefix(pp_qt);
String *pp_qprefix = SwigType_typedef_qualified(pp_tprefix);
if (Equal(qprefix, pp_qprefix)) {
String *templateargs = SwigType_templateargs(qt);
List *parms = SwigType_parmlist(templateargs);
Iterator pi = First(parms);
Parm *p = pi.item;
String *pp_templateargs = SwigType_templateargs(pp_qt);
List *pp_parms = SwigType_parmlist(pp_templateargs);
Iterator pp_pi = First(pp_parms);
Parm *pp = pp_pi.item;
if (p && pp) {
/* Implementation is limited to matching single parameter templates only for now */
int priority;
match = does_parm_match(p, pp, tscope, &priority);
if (match <= PartiallySpecializedNoMatch) {
*specialization_priority = priority;
} else {
*specialization_priority = priority + TEMPLATE_MATCH_PRIORITY;
}
}
Delete(pp_parms);
Delete(pp_templateargs);
Delete(parms);
Delete(templateargs);
}
Delete(pp_qprefix);
Delete(pp_tprefix);
Delete(qprefix);
Delete(tprefix);
}
Delete(pp_tsuffix);
Delete(pp_qt);
Delete(tsuffix);
Delete(qt);
}
} }
} }
/* /*
@ -828,7 +926,6 @@ static Node *template_locate(String *name, Parm *instantiated_parms, String *sym
/* Rank each template parameter against the desired template parameters then build a matrix of best matches */ /* Rank each template parameter against the desired template parameters then build a matrix of best matches */
possiblepartials = NewList(); possiblepartials = NewList();
{ {
char tmp[32];
List *partials; List *partials;
partials = Getattr(templ, "partials"); /* note that these partial specializations do not include explicit specializations */ partials = Getattr(templ, "partials"); /* note that these partial specializations do not include explicit specializations */
@ -852,12 +949,11 @@ static Node *template_locate(String *name, Parm *instantiated_parms, String *sym
if (ParmList_len(partialparms) == parms_len) { if (ParmList_len(partialparms) == parms_len) {
while (p && pp) { while (p && pp) {
SwigType *t; SwigType *t;
sprintf(tmp, "$%d", i);
t = Getattr(p, "type"); t = Getattr(p, "type");
if (!t) if (!t)
t = Getattr(p, "value"); t = Getattr(p, "value");
if (t) { if (t) {
EMatch match = does_parm_match(t, Getattr(pp, "type"), tmp, tscope, priorities_row + i - 1); EMatch match = does_parm_match(t, Getattr(pp, "type"), tscope, priorities_row + i - 1);
if (match < (int)PartiallySpecializedMatch) { if (match < (int)PartiallySpecializedMatch) {
all_parameters_match = 0; all_parameters_match = 0;
break; break;
@ -1062,7 +1158,8 @@ Node *Swig_cparse_template_locate(String *name, Parm *instantiated_parms, String
isclass = (Equal(Getattr(n, "templatetype"), "class")); isclass = (Equal(Getattr(n, "templatetype"), "class"));
if (isclass) { if (isclass) {
Parm *tparmsfound = Getattr(n, "templateparms"); Node *primary = Getattr(n, "primarytemplate");
Parm *tparmsfound = Getattr(primary ? primary : n, "templateparms");
int specialized = !tparmsfound; /* fully specialized (an explicit specialization) */ int specialized = !tparmsfound; /* fully specialized (an explicit specialization) */
int variadic = ParmList_variadic_parm(tparmsfound) != 0; int variadic = ParmList_variadic_parm(tparmsfound) != 0;
if (!specialized) { if (!specialized) {
@ -1171,15 +1268,16 @@ static int merge_parameters(ParmList *expanded_templateparms, ParmList *template
} }
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* mark_defaults() * use_mark_defaults()
* *
* Mark all the template parameters that are expanded from a default value * Mark and use all the template parameters that are expanded from a default value
* ----------------------------------------------------------------------------- */ * ----------------------------------------------------------------------------- */
static void mark_defaults(ParmList *defaults) { static void use_mark_defaults(ParmList *defaults) {
Parm *tp = defaults; Parm *tp = defaults;
while (tp) { while (tp) {
Setattr(tp, "default", "1"); Setattr(tp, "default", "1");
Setattr(tp, "type", Getattr(tp, "value"));
tp = nextSibling(tp); tp = nextSibling(tp);
} }
} }
@ -1222,12 +1320,12 @@ static void expand_defaults(ParmList *expanded_templateparms) {
* arguments filled in where necessary. * arguments filled in where necessary.
* ----------------------------------------------------------------------------- */ * ----------------------------------------------------------------------------- */
ParmList *Swig_cparse_template_parms_expand(ParmList *instantiated_parms, Node *primary) { ParmList *Swig_cparse_template_parms_expand(ParmList *instantiated_parms, Node *primary, Node *templ) {
ParmList *expanded_templateparms = 0; ParmList *expanded_templateparms = 0;
ParmList *templateparms = Getattr(primary, "templateparms");
if (Equal(Getattr(primary, "templatetype"), "class")) { if (Equal(Getattr(primary, "templatetype"), "class")) {
/* Templated class */ /* Templated class */
ParmList *templateparms = Getattr(primary, "templateparms");
expanded_templateparms = CopyParmList(instantiated_parms); expanded_templateparms = CopyParmList(instantiated_parms);
int variadic = merge_parameters(expanded_templateparms, templateparms); int variadic = merge_parameters(expanded_templateparms, templateparms);
/* Add default arguments from primary template */ /* Add default arguments from primary template */
@ -1235,7 +1333,7 @@ ParmList *Swig_cparse_template_parms_expand(ParmList *instantiated_parms, Node *
ParmList *defaults_start = ParmList_nth_parm(templateparms, ParmList_len(instantiated_parms)); ParmList *defaults_start = ParmList_nth_parm(templateparms, ParmList_len(instantiated_parms));
if (defaults_start) { if (defaults_start) {
ParmList *defaults = CopyParmList(defaults_start); ParmList *defaults = CopyParmList(defaults_start);
mark_defaults(defaults); use_mark_defaults(defaults);
expanded_templateparms = ParmList_join(expanded_templateparms, defaults); expanded_templateparms = ParmList_join(expanded_templateparms, defaults);
expand_defaults(expanded_templateparms); expand_defaults(expanded_templateparms);
} }
@ -1243,6 +1341,7 @@ ParmList *Swig_cparse_template_parms_expand(ParmList *instantiated_parms, Node *
} else { } else {
/* Templated function */ /* Templated function */
/* TODO: Default template parameters support was only added in C++11 */ /* TODO: Default template parameters support was only added in C++11 */
ParmList *templateparms = Getattr(templ, "templateparms");
expanded_templateparms = CopyParmList(instantiated_parms); expanded_templateparms = CopyParmList(instantiated_parms);
merge_parameters(expanded_templateparms, templateparms); merge_parameters(expanded_templateparms, templateparms);
} }