improved struct pointer pointer example
git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@7308 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
parent
f5bcace78c
commit
2ac9878ed5
1 changed files with 75 additions and 71 deletions
|
|
@ -5077,7 +5077,7 @@ public static void setHair(HairType h) {
|
||||||
|
|
||||||
public static HairType getHair() {
|
public static HairType getHair() {
|
||||||
return HairType.class.getEnumConstants()[exampleJNI.getHair()];
|
return HairType.class.getEnumConstants()[exampleJNI.getHair()];
|
||||||
}/
|
}
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -5989,15 +5989,14 @@ This example contains some useful functionality which you may want in your code.
|
||||||
|
|
||||||
<H3><a name="struct_pointer_pointer"></a>Struct pointer to pointer</H3>
|
<H3><a name="struct_pointer_pointer"></a>Struct pointer to pointer</H3>
|
||||||
<p>
|
<p>
|
||||||
Pointers to pointers are often used as output parameters in C code in factory type functions.
|
Pointers to pointers are often used as output parameters in C factory type functions.
|
||||||
These are a bit more tricky to handle.
|
These are a bit more tricky to handle.
|
||||||
Consider the following situation where a <tt>Butler</tt> can be created/hired and fired:
|
Consider the following situation where a <tt>Butler</tt> can be hired and fired:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="code">
|
<div class="code">
|
||||||
<pre>
|
<pre>
|
||||||
typedef struct
|
typedef struct {
|
||||||
{
|
|
||||||
int hoursAvailable;
|
int hoursAvailable;
|
||||||
char *greeting;
|
char *greeting;
|
||||||
} Butler;
|
} Butler;
|
||||||
|
|
@ -6031,39 +6030,61 @@ void FireButler(Butler *pButler) {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The memory ownership is very C oriented.
|
Let's take two approaches to wrapping this code.
|
||||||
We could make it slightly more object oriented and get the Java proxy class's finalizer call the <tt>FireButler()</tt> function to clean up the memory.
|
The first is to provide a functional interface, much like the original C interface.
|
||||||
The proxy class will thus take ownership of the memory and clean it up when no longer needed.
|
The following Java code shows how we intend the code to be used:
|
||||||
We will also ensure that the proxy class's public constructor does not actually create any C object.
|
|
||||||
The only way a Java user can then create a Butler is via the <tt>HireButler()</tt> method.
|
|
||||||
A number of typemaps and features are needed to implement this.
|
|
||||||
The code that follows implements does this and should be put in the interface file before SWIG parses the above C code.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="code">
|
<div class="code">
|
||||||
<pre>
|
<pre>
|
||||||
|
Butler jeeves = new Butler();
|
||||||
|
example.HireButler(jeeves);
|
||||||
|
System.out.println("Greeting: " + jeeves.getGreeting());
|
||||||
|
System.out.println("Availability: " + jeeves.getHoursAvailable() + " hours per day");
|
||||||
|
example.FireButler(jeeves);
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Resulting in the following output when run:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="shell">
|
||||||
|
<pre>
|
||||||
|
Greeting: At your service Sir
|
||||||
|
Availability: 24 hours per day
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Note the usage is very much like it would be used if we were writing C code, that is, explicit memory management is needed.
|
||||||
|
No C memory is allocated in the construction of the <tt>Butler</tt> proxy class and
|
||||||
|
the proxy class will not destroy the underlying C memory when it is collected.
|
||||||
|
A number of typemaps and features are needed to implement this approach.
|
||||||
|
The following interface file code should be placed before SWIG parses the above C code.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
%module example
|
||||||
|
|
||||||
|
// Do not generate the default proxy constructor or destructor
|
||||||
%nodefault Butler;
|
%nodefault Butler;
|
||||||
|
|
||||||
// Don't wrap the function which frees the memory
|
// Add in pure Java code proxy constructor
|
||||||
%ignore FireButler(Butler *pButler);
|
|
||||||
|
|
||||||
// Add in a custom proxy destructor
|
|
||||||
%extend Butler {
|
|
||||||
~Butler() {
|
|
||||||
FireButler(self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Typemaps for marshalling Butler **
|
|
||||||
%typemap(jni) Butler ** "jobject"
|
|
||||||
%typemap(jtype) Butler ** "Butler"
|
|
||||||
%typemap(jstype) Butler ** "Butler"
|
|
||||||
%typemap(javacode) Butler %{
|
%typemap(javacode) Butler %{
|
||||||
/** This constructor creates the proxy which initially doesn't own any C memory */
|
/** This constructor creates the proxy which initially does not create nor own any C memory */
|
||||||
public Butler() {
|
public Butler() {
|
||||||
this(0, false);
|
this(0, false);
|
||||||
}
|
}
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
// Type typemaps for marshalling Butler **
|
||||||
|
%typemap(jni) Butler ** "jobject"
|
||||||
|
%typemap(jtype) Butler ** "Butler"
|
||||||
|
%typemap(jstype) Butler ** "Butler"
|
||||||
|
|
||||||
|
// Typemaps for Butler ** as a parameter output type
|
||||||
%typemap(in) Butler ** (Butler *ppButler = 0) %{
|
%typemap(in) Butler ** (Butler *ppButler = 0) %{
|
||||||
$1 = &ppButler;
|
$1 = &ppButler;
|
||||||
%}
|
%}
|
||||||
|
|
@ -6074,83 +6095,66 @@ The code that follows implements does this and should be put in the interface fi
|
||||||
jlong cPtr = 0;
|
jlong cPtr = 0;
|
||||||
*(Butler **)(void *)&cPtr = *$1;
|
*(Butler **)(void *)&cPtr = *$1;
|
||||||
(*jenv)->SetLongField(jenv, $input, fid, cPtr);
|
(*jenv)->SetLongField(jenv, $input, fid, cPtr);
|
||||||
// Get Java proxy to take ownership of the C memory
|
|
||||||
fid = (*jenv)->GetFieldID(jenv, clazz, "swigCMemOwn", "Z");
|
|
||||||
(*jenv)->SetBooleanField(jenv, $input, fid, JNI_TRUE);
|
|
||||||
}
|
}
|
||||||
%typemap(javain) Butler ** "$javainput"
|
%typemap(javain) Butler ** "$javainput"
|
||||||
|
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Usage from Java is simply:
|
Note that the JNI code sets the proxy's <tt>swigCPtr</tt> member variable to point to the newly created object.
|
||||||
|
The <tt>swigCMemOwn</tt> remains unchanged (at false), so that the proxy does not own the memory.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The second approach offers a more object oriented interface to the Java user.
|
||||||
|
We do this by making the Java proxy class's
|
||||||
|
constructor call the <tt>HireButler()</tt> method to create the underlying C object.
|
||||||
|
Additionally we get the proxy to take ownership of the memory so that the
|
||||||
|
finalizer will call the <tt>FireButler()</tt> function.
|
||||||
|
The proxy class will thus take ownership of the memory and clean it up when no longer needed.
|
||||||
|
We will also prevent the user from being able to explicitly call the <tt>HireButler()</tt> and <tt>FireButler()</tt> functions.
|
||||||
|
Usage from Java will simply be:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="code">
|
<div class="code">
|
||||||
<pre>
|
<pre>
|
||||||
Butler jeeves = new Butler();
|
Butler jeeves = new Butler();
|
||||||
example.HireButler(jeeves);
|
|
||||||
System.out.println("Greeting: " + jeeves.getGreeting());
|
System.out.println("Greeting: " + jeeves.getGreeting());
|
||||||
System.out.println("Availability: " + jeeves.getHoursAvailable() + " hours per day");
|
System.out.println("Availability: " + jeeves.getHoursAvailable() + " hours per day");
|
||||||
jeeves.delete(); // optional
|
|
||||||
jeeves.delete(); // inadvertant multiple calls are safe, the memory is only deleted once
|
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Output when run is:
|
Note that the Butler class is used just like any other Java class and no extra coding by the user needs to be written to
|
||||||
<p>
|
clear up the underlying C memory as the finalizer will be called by the garbage collector which in turn will call the <tt>FireButler()</tt> function.
|
||||||
|
To implement this, we use the above interface file code but remove the <tt>javacode</tt> typemap and add the following:
|
||||||
<div class="shell">
|
|
||||||
<pre>
|
|
||||||
$ java main
|
|
||||||
Greeting: At your service Sir
|
|
||||||
Availability: 24 hours per day
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Note that the user can decide when the underlying C memory is free'd by calling the <tt>delete()</tt> method.
|
|
||||||
However this is not necessary and the garbage collector will collect the object and call the finalizer, which in turn calls <tt>delete()</tt> which in turn calls
|
|
||||||
<tt>FireButler()</tt>.
|
|
||||||
There are many variations on how this code could be wrapped.
|
|
||||||
For example the <tt>HireButler()</tt> method could be ignored and a proxy constructor added to call this method instead.
|
|
||||||
The code would be similar, except the <tt>javacode</tt> typemap would not be used and the following would be added:
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="code">
|
<div class="code">
|
||||||
<pre>
|
<pre>
|
||||||
// Don't wrap the HireButler method
|
// Don't expose the memory allocation/de-allocation functions
|
||||||
|
%ignore FireButler(Butler *pButler);
|
||||||
%ignore HireButler(Butler **ppButler);
|
%ignore HireButler(Butler **ppButler);
|
||||||
|
|
||||||
// Add custom proxy constructor which calls the HireButler method
|
// Add in a custom proxy constructor and destructor
|
||||||
%extend Butler {
|
%extend Butler {
|
||||||
Butler() {
|
Butler() {
|
||||||
Butler *pButler = 0;
|
Butler *pButler = 0;
|
||||||
HireButler(&pButler);
|
HireButler(&pButler);
|
||||||
return pButler;
|
return pButler;
|
||||||
}
|
}
|
||||||
|
~Butler() {
|
||||||
|
FireButler(self);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The following Java code would then be all that is necessary:
|
Not that the code in <tt>%extend</tt> is using a C++ type constructor and destructor, yet the generated code will still compile as C code,
|
||||||
</p>
|
see <a href="SWIG.html#SWIG_adding_member_functions">Adding member functions to C structures</a>.
|
||||||
|
The C functional interface has been completely morphed into an object-oriented interface and
|
||||||
<div class="code">
|
the Butler class would behave much like any pure Java class and feel more natural to Java users.
|
||||||
<pre>
|
|
||||||
Butler jeeves = new Butler();
|
|
||||||
System.out.println("Greeting: " + jeeves.getGreeting());
|
|
||||||
System.out.println("Availability: " + jeeves.getHoursAvailable() + " hours per day");
|
|
||||||
jeeves.delete(); // optional
|
|
||||||
jeeves.delete(); // inadvertant multiple calls are safe, the memory is only deleted once
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Other alternatives would be to have no proxy constructors/finalizers and to expose both of the C methods to Java users.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -6523,7 +6527,7 @@ Java classes without any finalizers generally speed up code execution as there i
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
However, you will have to be careful about memory management and make sure that you code in a call to the <tt>delete()</tt> member function.
|
However, you will have to be careful about memory management and make sure that you code in a call to the <tt>delete()</tt> member function.
|
||||||
This method calls the C++ destructor or <tt>free()</tt> for C code.
|
This method normally calls the C++ destructor or <tt>free()</tt> for C code.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue