From efd200ffe2bc9b3f620e73c2b6cda51b1960a38a Mon Sep 17 00:00:00 2001
From: William S Fulton
-If TYPE includes qualifiers (const, volatile, etc.), they are stripped to form a new stripped type
+If TYPE includes qualifiers (const, volatile, etc.), each qualifier is stripped one at a time to form a new stripped type
and the matching rules above are repeated on the stripped type.
+The left-most qualifier is stripped first, resulting in the right-most (or top-level) qualifier being stripped last.
+For example int const*const is first stripped to int *const then int *.
@@ -1056,8 +1059,8 @@ To find a typemap for the argument const char *s, SWIG will search for
+Compatibility note: SWIG-2.0.0 introduced stripping the qualifiers one step at a time. Prior versions
+stripped all qualifiers in one step.
+
const char *s Exact type and name match
const char * Exact type match
-char *s Type and name match (stripped qualifiers)
-char * Type match (stripped qualifiers)
+char *s Type and name match (qualifier stripped)
+char * Type match (qualifier stripped)
@@ -1097,6 +1100,11 @@ void F(int x[1000]); // int [ANY] rule (typemap 5)
+10.3.2 Typedef reductions matching
@@ -1280,7 +1288,7 @@ If the basic pattern matching rules result in no match being made, even after ty
the default typemap matching rules are used to look for a suitable typemap match.
These rules match a generic typemap based on the reserved SWIGTYPE base type.
For example pointers will use SWIGTYPE * and references will use SWIGTYPE &.
-More precisely, the rules are based on the C++ template partial specialization matching rules used
+More precisely, the rules are based on the C++ class template partial specialization matching rules used
by C++ compilers when looking for an appropriate partial template specialization.
This means that a match is chosen from the most specialized set of generic typemap types available. For example,
when looking for a match to int const *, the rules will prefer to match SWIGTYPE const *
@@ -1407,11 +1415,10 @@ Finally the best way to view the typemap matching rules in action is via the
Compatibility note: The default typemap matching rules were modified in SWIG-2.0.0 from a slightly
-simpler scheme to match the current C++ template partial specialization matching rules.
+simpler scheme to match the current C++ class template partial specialization matching rules.
@@ -1441,7 +1448,165 @@ but all subsequent arguments must match exactly.
-+For those intimately familiar with C++ templates, a comparison of the typemap matching rules and template type deduction is interesting. +The two areas considered are firstly the default typemaps and their similarities to partial template specialization and secondly, non-default typemaps and their similarities to full template specialization. +
+ ++For default (SWIGTYPE) typemaps the rules are inspired by C++ class template +partial specialization. For example, given partial specialization for T const& : +
+ +
+template <typename T> struct X { void a(); };
+template <typename T> struct X< T const& > { void b(); };
+
++The full (unspecialized) template is matched with most types, such as: +
+ ++X< int & > x1; x1.a(); ++
+and the following all match the T const& partial specialization: +
+ ++X< int *const& > x2; x2.b(); +X< int const*const& > x3; x3.b(); +X< int const& > x4; x4.b(); ++
+Now, given just these two default typemaps, where T is analogous to SWIGTYPE: +
+ +
+%typemap(...) SWIGTYPE { ... }
+%typemap(...) SWIGTYPE const& { ... }
+
++The generic default typemap SWIGTYPE is used with most types, such as +
+ ++int & ++
+and the following all match the SWIGTYPE const& typemap, just like the partial template matching: +
+ ++int *const& +int const*const& +int const& ++
+Note that the template and typemap matching rules are not identical for all default typemaps though, for example, with arrays. +
+ ++For non-default typemaps, one might expect SWIG to follow the fully specialized template rules. +This is nearly the case, but not quite. +Consider a very similar example to the earlier partially specialized template but this time there is a fully specialized template: +
+ +
+template <typename T> struct Y { void a(); };
+template <> struct Y< int const & > { void b(); };
+
++Only the one type matches the specialized template exactly: +
+ ++Y< int & > y1; y1.a(); +Y< int *const& > y2; y2.a(); +Y< int const *const& > y3; y3.a(); +Y< int const& > y4; y4.b(); // fully specialized match ++
+Given typemaps with the same types used for the template declared above, where T is again analogous to SWIGTYPE: +
+ +
+%typemap(...) SWIGTYPE { ... }
+%typemap(...) int const& { ... }
+
++The comparison between non-default typemaps and fully specialized single parameter templates turns out to be the same, as just the one type will match the non-default typemap: +
+ ++int & +int *const& +int const*const& +int const& // matches non-default typemap int const& ++
+However, if a non-const type is used instead: +
+ +
+%typemap(...) SWIGTYPE { ... }
+%typemap(...) int & { ... }
+
++then there is a clear difference to template matching as both the const and non-const types match the typemap: +
+ ++int & // matches non-default typemap int & +int *const& +int const*const& +int const& // matches non-default typemap int & ++
+There are other subtle differences such as typedef handling, but at least it should be clear that the typemap matching rules +are similar to those for specialized template handling. +
+ + +diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk index 308ff9f1e..64dea58b7 100644 --- a/Examples/test-suite/common.mk +++ b/Examples/test-suite/common.mk @@ -393,6 +393,7 @@ CPP_TEST_CASES += \ typemap_numinputs \ typemap_template \ typemap_out_optimal \ + typemap_qualifier_strip \ typemap_variables \ typemap_various \ typename \ diff --git a/Examples/test-suite/python/typemap_qualifier_strip_runme.py b/Examples/test-suite/python/typemap_qualifier_strip_runme.py new file mode 100644 index 000000000..5e466cf69 --- /dev/null +++ b/Examples/test-suite/python/typemap_qualifier_strip_runme.py @@ -0,0 +1,54 @@ +import typemap_qualifier_strip + +val = typemap_qualifier_strip.create_int(111) +if typemap_qualifier_strip.testA1(val) != 1234: + raise RuntimeError + +if typemap_qualifier_strip.testA2(val) != 1234: + raise RuntimeError + +if typemap_qualifier_strip.testA3(val) != 1234: + raise RuntimeError + +if typemap_qualifier_strip.testA4(val) != 1234: + raise RuntimeError + + +if typemap_qualifier_strip.testB1(val) != 111: + raise RuntimeError + +if typemap_qualifier_strip.testB2(val) != 111: + raise RuntimeError + +if typemap_qualifier_strip.testB3(val) != 111: + raise RuntimeError + +if typemap_qualifier_strip.testB4(val) != 111: + raise RuntimeError + + +if typemap_qualifier_strip.testC1(val) != 5678: + raise RuntimeError + +if typemap_qualifier_strip.testC2(val) != 111: + raise RuntimeError + +if typemap_qualifier_strip.testC3(val) != 5678: + raise RuntimeError + +if typemap_qualifier_strip.testC4(val) != 111: + raise RuntimeError + + +if typemap_qualifier_strip.testD1(val) != 111: + raise RuntimeError + +if typemap_qualifier_strip.testD2(val) != 3456: + raise RuntimeError + +if typemap_qualifier_strip.testD3(val) != 111: + raise RuntimeError + +if typemap_qualifier_strip.testD4(val) != 111: + raise RuntimeError + diff --git a/Examples/test-suite/typemap_qualifier_strip.i b/Examples/test-suite/typemap_qualifier_strip.i new file mode 100644 index 000000000..d91a7b109 --- /dev/null +++ b/Examples/test-suite/typemap_qualifier_strip.i @@ -0,0 +1,76 @@ +%module typemap_qualifier_strip + +%typemap(in) int *ptr { + int temp = 1234; + $1 = &temp; +} + +%typemap(in) int *const ptrConst { + int temp = 5678; + $1 = &temp; +} + +%typemap(in) int const* constPtr { + int temp = 3456; + $1 = &temp; +} + +%inline %{ +int *create_int(int newval) { + static int val = 0; + val = newval; + return &val; +} +int testA1(int const*const ptr) { + return *ptr; +} +int testA2(int const* ptr) { + return *ptr; +} +int testA3(int *const ptr) { + return *ptr; +} +int testA4(int * ptr) { + return *ptr; +} + +int testB1(int const*const p) { + return *p; +} +int testB2(int const* p) { + return *p; +} +int testB3(int *const p) { + return *p; +} +int testB4(int * p) { + return *p; +} + +int testC1(int const*const ptrConst) { + return *ptrConst; +} +int testC2(int const* ptrConst) { + return *ptrConst; +} +int testC3(int *const ptrConst) { + return *ptrConst; +} +int testC4(int * ptrConst) { + return *ptrConst; +} + +int testD1(int const*const constPtr) { + return *constPtr; +} +int testD2(int const* constPtr) { + return *constPtr; +} +int testD3(int *const constPtr) { + return *constPtr; +} +int testD4(int * constPtr) { + return *constPtr; +} +%} + diff --git a/Source/Swig/stype.c b/Source/Swig/stype.c index 533b8195f..c984d639b 100644 --- a/Source/Swig/stype.c +++ b/Source/Swig/stype.c @@ -357,8 +357,8 @@ SwigType *SwigType_default_create(SwigType *ty) { * SwigType_default_deduce() * * This function implements type deduction used in the typemap matching rules - * and is very close to the type deduction used in partial template specialization - * matching in that the most specialized type is always chosen. + * and is very close to the type deduction used in partial template class + * specialization matching in that the most specialized type is always chosen. * SWIGTYPE is used as the generic type. The basic idea is to repeatedly call * this function to find a deduced type unless until nothing matches. * diff --git a/Source/Swig/swig.h b/Source/Swig/swig.h index 2b2c7f4cf..f90a5ffb1 100644 --- a/Source/Swig/swig.h +++ b/Source/Swig/swig.h @@ -159,6 +159,7 @@ extern "C" { extern int SwigType_isenum(SwigType *t); extern int SwigType_check_decl(SwigType *t, const_String_or_char_ptr decl); extern SwigType *SwigType_strip_qualifiers(SwigType *t); + extern SwigType *SwigType_strip_single_qualifier(SwigType *t); extern SwigType *SwigType_functionpointer_decompose(SwigType *t); extern String *SwigType_base(const SwigType *t); extern String *SwigType_namestr(const SwigType *t); diff --git a/Source/Swig/typemap.c b/Source/Swig/typemap.c index 37f8c3d82..cbe881577 100644 --- a/Source/Swig/typemap.c +++ b/Source/Swig/typemap.c @@ -698,11 +698,11 @@ static Hash *typemap_search(const_String_or_char_ptr tmap_method, SwigType *type Hash *backup = 0; SwigType *primitive = 0; SwigType *ctype = 0; + SwigType *ctype_unstripped = 0; int ts; int isarray; const String *cname = 0; const String *cqualifiedname = 0; - SwigType *unstripped = 0; String *tm_method = typemap_method_name(tmap_method); int debug_display = (in_typemap_search_multi == 0) && typemap_search_debug; @@ -718,7 +718,8 @@ static Hash *typemap_search(const_String_or_char_ptr tmap_method, SwigType *type Delete(typestr); } while (ts >= 0) { - ctype = type; + ctype = Copy(type); + ctype_unstripped = Copy(ctype); while (ctype) { /* Try to get an exact type-match */ tm = get_typemap(ts, ctype); @@ -751,29 +752,25 @@ static Hash *typemap_search(const_String_or_char_ptr tmap_method, SwigType *type goto ret_result; } - /* No match so far. If the type is unstripped, we'll strip its - qualifiers and check. Otherwise, we'll try to resolve a typedef */ - - if (!unstripped) { - unstripped = ctype; - ctype = SwigType_strip_qualifiers(ctype); - if (!Equal(ctype, unstripped)) - continue; /* Types are different */ - Delete(ctype); - ctype = unstripped; - unstripped = 0; - } + /* No match so far - try with a qualifier stripped (strip one qualifier at a time until none remain) + * The order of stripping in SwigType_strip_single_qualifier is used to provide some sort of consistency + * with the default (SWIGTYPE) typemap matching rules for the first qualifier to be stripped. */ { - String *octype; - if (unstripped) { - Delete(ctype); - ctype = unstripped; - unstripped = 0; + SwigType *oldctype = ctype; + ctype = SwigType_strip_single_qualifier(oldctype); + if (!Equal(ctype, oldctype)) { + Delete(oldctype); + continue; } - octype = ctype; - ctype = SwigType_typedef_resolve(ctype); - if (octype != type) - Delete(octype); + Delete(oldctype); + } + + /* Once all qualifiers are stripped try resolve a typedef */ + { + SwigType *oldctype = ctype; + ctype = SwigType_typedef_resolve(ctype_unstripped); + Delete(oldctype); + ctype_unstripped = Copy(ctype); } } @@ -802,12 +799,10 @@ static Hash *typemap_search(const_String_or_char_ptr tmap_method, SwigType *type ret_result: Delete(primitive); - if ((unstripped) && (unstripped != type)) - Delete(unstripped); if (matchtype) *matchtype = Copy(ctype); - if (type != ctype) - Delete(ctype); + Delete(ctype); + Delete(ctype_unstripped); return result; } diff --git a/Source/Swig/typeobj.c b/Source/Swig/typeobj.c index a2e23e52d..074bbf904 100644 --- a/Source/Swig/typeobj.c +++ b/Source/Swig/typeobj.c @@ -1125,3 +1125,62 @@ SwigType *SwigType_strip_qualifiers(SwigType *t) { } return r; } + +/* ----------------------------------------------------------------------------- + * SwigType_strip_single_qualifier() + * + * If the type contains a qualifier, strip one qualifier and return a new type. + * The left most qualifier is stripped first (when viewed as C source code) but + * this is the equivalent to the right most qualifier using SwigType notation. + * Example: + * r.q(const).p.q(const).int => r.q(const).p.int + * r.q(const).p.int => r.p.int + * r.p.int => r.p.int + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_strip_single_qualifier(SwigType *t) { + static Hash *memoize_stripped = 0; + SwigType *r = 0; + List *l; + int numitems; + + if (!memoize_stripped) + memoize_stripped = NewHash(); + r = Getattr(memoize_stripped, t); + if (r) + return Copy(r); + + l = SwigType_split(t); + + numitems = Len(l); + if (numitems >= 2) { + int item; + /* iterate backwards from last but one item */ + for (item = numitems - 2; item >= 0; --item) { + String *subtype = Getitem(l, item); + if (SwigType_isqualifier(subtype)) { + Iterator it; + Delitem(l, item); + r = NewStringEmpty(); + for (it = First(l); it.item; it = Next(it)) { + Append(r, it.item); + } + break; + } + } + } + if (!r) + r = Copy(t); + + Delete(l); + { + String *key, *value; + key = Copy(t); + value = Copy(r); + Setattr(memoize_stripped, key, value); + Delete(key); + Delete(value); + } + return r; +} +