From 2ac9878ed5e386995fe95e02eef102c49bdaf3f4 Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Mon, 20 Jun 2005 20:10:31 +0000 Subject: [PATCH] improved struct pointer pointer example git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@7308 626c5289-ae23-0410-ae9c-e8d60b6d4f22 --- SWIG/Doc/Manual/Java.html | 146 ++++++++++++++++++++------------------ 1 file changed, 75 insertions(+), 71 deletions(-) diff --git a/SWIG/Doc/Manual/Java.html b/SWIG/Doc/Manual/Java.html index 438d4d6f3..e30cd4af8 100644 --- a/SWIG/Doc/Manual/Java.html +++ b/SWIG/Doc/Manual/Java.html @@ -5077,7 +5077,7 @@ public static void setHair(HairType h) { public static HairType getHair() { return HairType.class.getEnumConstants()[exampleJNI.getHair()]; -}/ +} @@ -5989,15 +5989,14 @@ This example contains some useful functionality which you may want in your code.

Struct pointer to pointer

-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. -Consider the following situation where a Butler can be created/hired and fired: +Consider the following situation where a Butler can be hired and fired:

-typedef struct 
-{
+typedef struct {
   int hoursAvailable;
   char *greeting;
 } Butler;
@@ -6031,39 +6030,61 @@ void FireButler(Butler *pButler) {
 

-The memory ownership is very C oriented. -We could make it slightly more object oriented and get the Java proxy class's finalizer call the FireButler() function to clean up the memory. -The proxy class will thus take ownership of the memory and clean it up when no longer needed. -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 HireButler() 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. +Let's take two approaches to wrapping this code. +The first is to provide a functional interface, much like the original C interface. +The following Java code shows how we intend the code to be used:

+    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);
+
+
+ +

+Resulting in the following output when run: +

+ +
+
+Greeting:     At your service Sir
+Availability: 24 hours per day
+
+
+ +

+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 Butler 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. +

+ +
+
+%module example
+
+// Do not generate the default proxy constructor or destructor
 %nodefault Butler;
 
-// Don't wrap the function which frees the memory
-%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"
+// Add in pure Java code proxy constructor
 %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() {
     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) %{
   $1 = &ppButler;
 %}
@@ -6074,83 +6095,66 @@ The code that follows implements does this and should be put in the interface fi
   jlong cPtr = 0;
   *(Butler **)(void *)&cPtr = *$1;
   (*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"
-
 

-Usage from Java is simply: +Note that the JNI code sets the proxy's swigCPtr member variable to point to the newly created object. +The swigCMemOwn remains unchanged (at false), so that the proxy does not own the memory. +

+ +

+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 HireButler() 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 FireButler() 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 HireButler() and FireButler() functions. +Usage from Java will simply be:

 Butler jeeves = new Butler();
-example.HireButler(jeeves);
 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
 

-Output when run is: -

- -

-
-$ java main
-Greeting:     At your service Sir
-Availability: 24 hours per day
-
-
- -

-Note that the user can decide when the underlying C memory is free'd by calling the delete() method. -However this is not necessary and the garbage collector will collect the object and call the finalizer, which in turn calls delete() which in turn calls -FireButler(). -There are many variations on how this code could be wrapped. -For example the HireButler() method could be ignored and a proxy constructor added to call this method instead. -The code would be similar, except the javacode typemap would not be used and the following would be added: +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 +clear up the underlying C memory as the finalizer will be called by the garbage collector which in turn will call the FireButler() function. +To implement this, we use the above interface file code but remove the javacode typemap and add the following:

-// Don't wrap the HireButler method
+// Don't expose the memory allocation/de-allocation functions
+%ignore FireButler(Butler *pButler);
 %ignore HireButler(Butler **ppButler);
 
-// Add custom proxy constructor which calls the HireButler method
+// Add in a custom proxy constructor and destructor
 %extend Butler {
   Butler() {
     Butler *pButler = 0;
     HireButler(&pButler);
     return pButler;
   }
+  ~Butler() {
+     FireButler(self);
+   }
 }
 

-The following Java code would then be all that is necessary: -

- -
-
-    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
-
-
- -

-Other alternatives would be to have no proxy constructors/finalizers and to expose both of the C methods to Java users. +Not that the code in %extend is using a C++ type constructor and destructor, yet the generated code will still compile as C code, +see Adding member functions to C structures. +The C functional interface has been completely morphed into an object-oriented interface and +the Butler class would behave much like any pure Java class and feel more natural to Java users.

@@ -6523,7 +6527,7 @@ Java classes without any finalizers generally speed up code execution as there i

However, you will have to be careful about memory management and make sure that you code in a call to the delete() member function. -This method calls the C++ destructor or free() for C code. +This method normally calls the C++ destructor or free() for C code.