Add %proxycode directive for adding code into proxy classes for C#, D and Java

This commit is contained in:
William S Fulton 2017-01-13 20:42:12 +00:00
parent 88e2d02ead
commit 3d2e57b0f2
18 changed files with 478 additions and 5 deletions

View File

@ -7,6 +7,24 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
Version 3.0.12 (in progress)
============================
2017-01-13: wsfulton
[C# D Java] Add new %proxycode directive which is a macro for %insert("proxycode").
This is a way of adding pure C#/D/Java code into the appropriate proxy class, eg:
%extend Proxy2 {
%proxycode %{
public int proxycode2(int i) {
return i+2;
}
%}
}
%inline %{
struct Proxy2 {};
%}
There will then be a pure Java/C#/D method called proxycode2 in the Proxy2 class.
2016-12-31: ajrheading1
Issue #860 - Remove use of std::unary_function and std::binary_function
which is deprecated in C++11.

View File

@ -1016,6 +1016,7 @@
<ul>
<li><a href="Java.html#Java_helper_functions">C/C++ helper functions</a>
<li><a href="Java.html#Java_class_extension">Class extension with %extend</a>
<li><a href="Java.html#Java_proxycode">Class extension with %proxycode</a>
<li><a href="Java.html#Java_exception_handling">Exception handling with %exception and %javaexception</a>
<li><a href="Java.html#Java_method_access">Method access with %javamethodmodifiers</a>
</ul>

View File

@ -174,6 +174,9 @@
<p><a name="D_class_code_typemaps"></a><tt>dconstructor</tt>, <tt>ddestructor</tt>, <tt>ddispose</tt> and <tt>ddispose_derived</tt> are used to generate the class constructor, destructor and <tt>dispose()</tt> method, respectively. The auxiliary code for handling the pointer to the C++ object is stored in <tt>dbody</tt> and <tt>dbody_derived</tt>. You can override them for specific types.</p>
<p>
Code can also be injected into the D proxy class using <tt>%proxycode</tt>.
</p>
<H3><a name="D_special_variables">22.3.7 Special variable macros</a></H3>

View File

@ -100,6 +100,7 @@
<ul>
<li><a href="#Java_helper_functions">C/C++ helper functions</a>
<li><a href="#Java_class_extension">Class extension with %extend</a>
<li><a href="#Java_proxycode">Class extension with %proxycode</a>
<li><a href="#Java_exception_handling">Exception handling with %exception and %javaexception</a>
<li><a href="#Java_method_access">Method access with %javamethodmodifiers</a>
</ul>
@ -4363,7 +4364,144 @@ Vector(2, 3, 4)
in any way---the extensions only show up in the Java interface.
</p>
<H3><a name="Java_exception_handling">25.7.3 Exception handling with %exception and %javaexception</a></H3>
<H3><a name="Java_proxycode">25.7.3 Class extension with %proxycode</a></H3>
<p>
The previous section described how to extend a wrapped class with C or C++ code.
This section describes how to extend a wrapped class with Java code instead of C/C++ code.
The <tt>%proxycode</tt> directive is used and is just a macro for <tt>%insert("proxycode")</tt>.
The <a href="SWIG.html#SWIG_nn42">Code insertion block</a> section describes the <tt>%insert</tt> directive.
The section of code for insertion is "proxycode", that is, the Java proxy class.
This directive must hence only be used within the scope of a class, otherwise it is silently ignored.
There are two common ways to get the scope correct.
</p>
<p>
The first is to use <tt>%proxycode</tt> inside a class that SWIG parses, for example a <tt>toString()</tt> method can be added to a C++ class using pure Java code.
A C++ header file can mix C++ and Java code inside the C++ class as follows:
</p>
<div class="code">
<pre>
// flag.h header file
class Flag {
bool flag;
public:
Flag(bool flag) : flag(flag) {}
bool FetchFlag() { return flag; }
#if defined(SWIG)
%proxycode %{
public String toString() {
boolean flag = FetchFlag();
return Boolean.toString(flag);
}
%}
#endif
};
</pre>
</div>
<p>
and wrapped using:
</p>
<div class="code">
<pre>
%{
#include "flag.h"
%}
%include "flag.h"
</pre>
</div>
<p>
The second is to use <tt>%proxycode</tt> within <tt>%extend</tt> as everything within a <tt>%extend</tt> block is effectively within the scope of the class, for example:
</p>
<div class="code">
<pre>
// flag.h header file
class Flag {
bool flag;
public:
Flag(bool flag) : flag(flag) {}
bool FetchFlag() { return flag; }
};
</pre>
</div>
<p>
and wrapped using:
</p>
<div class="code">
<pre>
%{
#include "flag.h"
%}
%include "flag.h"
%extend Flag {
#if defined(SWIG)
%proxycode %{
public String toString() {
boolean flag = FetchFlag();
return Boolean.toString(flag);
}
%}
#endif
}
</pre>
</div>
<p>
There is some very limited support of typemaps within a <tt>%proxycode</tt> block.
A useful trick is to obtain the Java type for a given C/C++ type using the <a href="Typemaps.html#Typemaps_special_macro_typemap">$typemap</a> special macro.
The following C++ template demonstrates this:
</p>
<div class="code">
<pre>
%inline %{
template&lt;typename T&gt; struct Value {
T value;
Value(const T&amp; val) : value(val) {}
};
%}
%extend Value {
%proxycode %{
public String toString() {
// Note template type expansion is supported, so T is expanded to 'unsigned int' in this example
// and $typemap(jstype, unsigned int) in turn is expanded to 'long'
$typemap(jstype, T) val = getValue();
return "$javaclassname value: " + val + " Java type: $typemap(jstype, T) JNI type: $typemap(jni, T)";
}
%}
}
%template(ValueUnsignedInt) Value&lt;unsigned int&gt;;
</pre>
</div>
<p>
The generated Java contains the expanded special variable and macro resulting in Java proxy code:
</p>
<div class="code">
<pre>
public class ValueUnsignedInt {
...
public String toString() {
long val = getValue();
return "ValueUnsignedInt value: " + val + " Java type: long JNI type: jlong";
}
}
</pre>
</div>
<H3><a name="Java_exception_handling">25.7.4 Exception handling with %exception and %javaexception</a></H3>
<p>
@ -4522,7 +4660,7 @@ to raise exceptions. See the <a href="Library.html#Library">SWIG Library</a> ch
The typemap example <a href="#Java_exception_typemap">Handling C++ exception specifications as Java exceptions</a> provides further exception handling capabilities.
</p>
<H3><a name="Java_method_access">25.7.4 Method access with %javamethodmodifiers</a></H3>
<H3><a name="Java_method_access">25.7.5 Method access with %javamethodmodifiers</a></H3>
<p>

View File

@ -3174,6 +3174,7 @@ the module upon loading.
<H3><a name="SWIG_nn42">5.6.2 Code insertion blocks</a></H3>
<p>
The <tt>%insert</tt> directive enables inserting blocks of code into a given section of the generated code.
It can be used in one of two ways:

View File

@ -335,6 +335,7 @@ CPP_TEST_CASES += \
preproc_constants \
primitive_ref \
private_assign \
proxycode \
protected_rename \
pure_virtual \
redefined \

View File

@ -0,0 +1,33 @@
using System;
using proxycodeNamespace;
public class proxycode_runme {
public static void Main() {
if (new Proxy1().proxycode1(100) != 101)
throw new Exception("Fail");
if (new Proxy2().proxycode2a(100) != 102)
throw new Exception("Fail");
if (new Proxy2().proxycode2b(100) != 102)
throw new Exception("Fail");
if (new Proxy3().proxycode3(100) != 103)
throw new Exception("Fail");
if (new Proxy4().proxycode4(100) != 104)
throw new Exception("Fail");
if (new Proxy4.Proxy4Nested().proxycode4nested(100) != 144)
throw new Exception("Fail");
if (new Proxy5a().proxycode5((short)100) != (short)100)
throw new Exception("Fail");
if (new Proxy5b().proxycode5(100) != 100)
throw new Exception("Fail");
if (new Proxy5b().proxycode5(100, 100) != 255)
throw new Exception("Fail");
uint t1 = 10;
uint t2 = 100;
Proxy6 p = new Proxy6().proxyUseT(t1, t2);
p.useT(t1, t2);
}
}

View File

@ -0,0 +1,41 @@
module proxycode_runme;
import std.exception;
import proxycode.Proxy1;
import proxycode.Proxy2;
import proxycode.Proxy3;
import proxycode.Proxy4;
import proxycode.Proxy5a;
import proxycode.Proxy5b;
import proxycode.Proxy6;
void main() {
if (new Proxy1().proxycode1(100) != 101)
throw new Exception("Fail");
if (new Proxy1().proxycode1(100) != 101)
throw new Exception("Fail");
if (new Proxy2().proxycode2a(100) != 102)
throw new Exception("Fail");
if (new Proxy2().proxycode2b(100) != 102)
throw new Exception("Fail");
if (new Proxy3().proxycode3(100) != 103)
throw new Exception("Fail");
if (new Proxy4().proxycode4(100) != 104)
throw new Exception("Fail");
// if (new Proxy4.Proxy4Nested().proxycode4nested(100) != 144)
// throw new Exception("Fail");
if (new Proxy5a().proxycode5(100) != 100)
throw new Exception("Fail");
if (new Proxy5b().proxycode5(100) != 100)
throw new Exception("Fail");
if (new Proxy5b().proxycode5(100, 100) != 255)
throw new Exception("Fail");
uint t1 = 10;
uint t2 = 100;
Proxy6 p = new Proxy6().proxyUseT(t1, t2);
p.useT(t1, t2);
}

View File

@ -0,0 +1,42 @@
import proxycode.*;
public class proxycode_runme {
static {
try {
System.loadLibrary("proxycode");
} catch (UnsatisfiedLinkError e) {
System.err.println("Native code library failed to load. See the chapter on Dynamic Linking Problems in the SWIG Java documentation for help.\n" + e);
System.exit(1);
}
}
public static void main(String argv[]) throws Throwable
{
if (new Proxy1().proxycode1(100) != 101)
throw new RuntimeException("Fail");
if (new Proxy2().proxycode2a(100) != 102)
throw new RuntimeException("Fail");
if (new Proxy2().proxycode2b(100) != 102)
throw new RuntimeException("Fail");
if (new Proxy3().proxycode3(100) != 103)
throw new RuntimeException("Fail");
if (new Proxy4().proxycode4(100) != 104)
throw new RuntimeException("Fail");
if (new Proxy4.Proxy4Nested().proxycode4nested(100) != 144)
throw new RuntimeException("Fail");
if (new Proxy5a().proxycode5((short)100) != (short)100)
throw new RuntimeException("Fail");
if (new Proxy5b().proxycode5(100) != 100)
throw new RuntimeException("Fail");
if (new Proxy5b().proxycode5(100, 100) != 255)
throw new RuntimeException("Fail");
long t1 = 10;
long t2 = 100;
Proxy6 p = new Proxy6().proxyUseT(t1, t2);
p.useT(t1, t2);
}
}

View File

@ -0,0 +1,141 @@
%module proxycode
%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Proxy4::Proxy4Nested;
#if defined(SWIGJAVA) || defined(SWIGCSHARP) || defined(SWIGD)
%{
struct Proxy1 {};
%}
struct Proxy1 {
%proxycode %{
public int proxycode1(int i) {
return i+1;
}
%}
};
%proxycode %{
this should be ignored as it is not in scope of a class
%}
%extend Proxy2 {
%proxycode %{
public int proxycode2a(int i) {
return i+2;
}
%}
}
%extend Proxy2 {
%proxycode %{
public int proxycode2b(int i) {
return i+2;
}
%}
}
%inline %{
struct Proxy2 {};
struct Proxy3 {};
struct Proxy4 {
struct Proxy4Nested {};
};
%}
%extend Proxy3 {
%proxycode %{
public int proxycode3(int i) {
return i+3;
}
%}
}
%extend Proxy4 {
%proxycode %{
public int proxycode4(int i) {
return i+4;
}
%}
}
%extend Proxy4::Proxy4Nested {
%proxycode %{
public int proxycode4nested(int i) {
return i+44;
}
%}
}
%extend TemplateProxy {
%proxycode %{
public T proxycode5(T i) {
return i;
}
%}
}
%extend TemplateProxy<int> {
%proxycode %{
public int proxycode5(int i, int j) {
return i+j+55;
}
%}
}
%inline %{
template <typename T> struct TemplateProxy {};
%}
%template(Proxy5a) TemplateProxy<short>;
%template(Proxy5b) TemplateProxy<int>;
%inline %{
template <typename T> struct TypemapProxy {
T useT(T t1, T const& t2) {
return t1+t2;
}
};
%}
%extend TypemapProxy {
#if defined(SWIGJAVA)
%proxycode %{
public $javaclassname proxyUseT(long t1, long t2) {
$typemap(jstype, unsigned int) tt1 = t1;
$typemap(jstype, unsigned int const&) tt2 = t2;
long ret = useT(tt1, tt2);
if (ret != t1+t2)
throw new RuntimeException("wrong sum");
return this;
}
%}
#elif defined(SWIGCSHARP)
%proxycode %{
public $csclassname proxyUseT(uint t1, uint t2) {
$typemap(cstype, unsigned int) tt1 = t1;
$typemap(cstype, unsigned int const&) tt2 = t2;
uint ret = useT(tt1, tt2);
if (ret != t1+t2)
throw new System.Exception("wrong sum");
return this;
}
%}
#elif defined(SWIGD)
%proxycode %{
public $dclassname proxyUseT(uint t1, uint t2) {
$typemap(dtype, unsigned int) tt1 = t1;
$typemap(dtype, unsigned int const&) tt2 = t2;
uint ret = useT(tt1, tt2);
if (ret != t1+t2)
throw new Exception("wrong sum");
return this;
}
%}
#else
#error "missing test"
#endif
}
%template(Proxy6) TypemapProxy<unsigned int>;
#endif

View File

@ -995,6 +995,7 @@ SWIG_CSBODY_TYPEWRAPPER(internal, protected, internal, SWIGTYPE)
#define %csmethodmodifiers %feature("cs:methodmodifiers")
#define %csnothrowexception %feature("except")
#define %csattributes %feature("cs:attributes")
#define %proxycode %insert("proxycode")
%pragma(csharp) imclassclassmodifiers="class"
%pragma(csharp) moduleclassmodifiers="public class"

View File

@ -8,3 +8,4 @@
#define %dconstvalue(value) %feature("d:constvalue",value)
#define %dmethodmodifiers %feature("d:methodmodifiers")
#define %dnothrowexception %feature("except")
#define %proxycode %insert("proxycode")

View File

@ -1317,6 +1317,7 @@ SWIG_PROXY_CONSTRUCTOR(true, true, SWIGTYPE)
#define %javaexception(exceptionclasses) %feature("except",throws=exceptionclasses)
#define %nojavaexception %feature("except","0",throws="")
#define %clearjavaexception %feature("except","",throws="")
#define %proxycode %insert("proxycode")
%pragma(java) jniclassclassmodifiers="public class"
%pragma(java) moduleclassmodifiers="public class"

View File

@ -1584,11 +1584,23 @@ public:
* ----------------------------------------------------------------------------- */
virtual int insertDirective(Node *n) {
int ret = SWIG_OK;
String *code = Getattr(n, "code");
String *section = Getattr(n, "section");
Replaceall(code, "$module", module_class_name);
Replaceall(code, "$imclassname", imclass_name);
Replaceall(code, "$dllimport", dllimport);
return Language::insertDirective(n);
if (!ImportMode && (Cmp(section, "proxycode") == 0)) {
if (proxy_class_code) {
Swig_typemap_replace_embedded_typemap(code, n);
int offset = Len(code) > 0 && *Char(code) == '\n' ? 1 : 0;
Printv(proxy_class_code, Char(code) + offset, "\n", NIL);
}
} else {
ret = Language::insertDirective(n);
}
return ret;
}
/* -----------------------------------------------------------------------------

View File

@ -717,9 +717,20 @@ public:
* D::insertDirective()
* --------------------------------------------------------------------------- */
virtual int insertDirective(Node *n) {
int ret = SWIG_OK;
String *code = Getattr(n, "code");
String *section = Getattr(n, "section");
replaceModuleVariables(code);
return Language::insertDirective(n);
if (!ImportMode && (Cmp(section, "proxycode") == 0)) {
if (proxy_class_body_code) {
Swig_typemap_replace_embedded_typemap(code, n);
Printv(proxy_class_body_code, code, NIL);
}
} else {
ret = Language::insertDirective(n);
}
return ret;
}
/* ---------------------------------------------------------------------------

View File

@ -1612,10 +1612,22 @@ public:
* ----------------------------------------------------------------------------- */
virtual int insertDirective(Node *n) {
int ret = SWIG_OK;
String *code = Getattr(n, "code");
String *section = Getattr(n, "section");
Replaceall(code, "$module", module_class_name);
Replaceall(code, "$imclassname", imclass_name);
return Language::insertDirective(n);
if (!ImportMode && (Cmp(section, "proxycode") == 0)) {
if (proxy_class_code) {
Swig_typemap_replace_embedded_typemap(code, n);
int offset = Len(code) > 0 && *Char(code) == '\n' ? 1 : 0;
Printv(proxy_class_code, Char(code) + offset, "\n", NIL);
}
} else {
ret = Language::insertDirective(n);
}
return ret;
}
/* -----------------------------------------------------------------------------

View File

@ -400,6 +400,7 @@ extern int ParmList_is_compactdefargs(ParmList *p);
extern void Swig_typemap_clear(const_String_or_char_ptr tmap_method, ParmList *pattern);
extern int Swig_typemap_apply(ParmList *srcpat, ParmList *destpat);
extern void Swig_typemap_clear_apply(ParmList *pattern);
extern void Swig_typemap_replace_embedded_typemap(String *s, Node *file_line_node);
extern void Swig_typemap_debug(void);
extern void Swig_typemap_search_debug_set(void);
extern void Swig_typemap_used_debug_set(void);

View File

@ -1876,6 +1876,21 @@ static List *split_embedded_typemap(String *s) {
return args;
}
/* -----------------------------------------------------------------------------
* Swig_typemap_replace_embedded_typemap()
*
* For special variable macro $typemap(...) expansion outside of typemaps.
* Only limited usage works as most typemap special variables ($1, $input etc)
* are not expanded correctly outside of typemaps.
* ----------------------------------------------------------------------------- */
void Swig_typemap_replace_embedded_typemap(String *s, Node *file_line_node) {
Setfile(s, Getfile(file_line_node));
Setline(s, Getline(file_line_node));
Replaceall(s, "$typemap", "$TYPEMAP");
replace_embedded_typemap(s, 0, 0, file_line_node);
}
/* -----------------------------------------------------------------------------
* replace_embedded_typemap()
*