diff --git a/CHANGES.current b/CHANGES.current index 0a707a918..287a97e8f 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -1,6 +1,14 @@ Version 2.0.0 (in progress) ============================ +2010-05-01: wsfulton + Typemap matching enhancement for non-default typemaps. Previously all + qualifiers were stripped in one step, now they are stripped one at a time + starting with the left most qualifier. For example, int const*const + is first stripped to int *const then int *. + + *** POTENTIAL INCOMPATIBILITY *** + 2010-04-25: bhy [Python] Fix #2985655 - broken constructor renaming. @@ -37,7 +45,7 @@ Version 2.0.0 (in progress) Numerous subtle typemap matching rule fixes when using the default type. The typemap matching rules are to take a type and find the best default typemap (SWIGTYPE, SWIGTYPE* etc), then look for the next best match by reducing the chosen default type. The type deduction - now follows C++ template partial specialization matching rules. + now follows C++ class template partial specialization matching rules. Below are the set of changes made showing the default type deduction along with the old reduced type and the new version of the reduced type: diff --git a/Doc/Manual/Contents.html b/Doc/Manual/Contents.html index a99fd1885..242b86429 100644 --- a/Doc/Manual/Contents.html +++ b/Doc/Manual/Contents.html @@ -351,6 +351,7 @@
-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
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) +
+Compatibility note: SWIG-2.0.0 introduced stripping the qualifiers one step at a time. Prior versions +stripped all qualifiers in one step. +
+@@ -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; +} +