1 /** Creates a pool for the type and sets SWIG to use the pool instead of creating a new java object every time. 2 * TODO: Add better pointer support 3 * @author Xoppa */ 4 %define CREATE_POOLED_OBJECT_EXT(CTYPE, JTYPE, _JCLASS) 5 6 // Add pooling to the java class 7 %typemap(javacode) CTYPE %{ 8 /** Temporary instance, use by native methods that return a JTYPE instance */ 9 protected final static JTYPE temp = new JTYPE(0, false); 10 public static JTYPE internalTemp(long cPtr, boolean own) { 11 temp.reset(cPtr, own); 12 return temp; 13 } 14 /** Pool of JTYPE instances, used by director interface to provide the arguments. */ 15 protected static final com.badlogic.gdx.utils.Pool<JTYPE> pool = new com.badlogic.gdx.utils.Pool<JTYPE>() { 16 @Override 17 protected JTYPE newObject() { 18 return new JTYPE(0, false); 19 } 20 }; 21 /** Reuses a previous freed instance or creates a new instance and set it to reflect the specified native object */ 22 public static JTYPE obtain(long cPtr, boolean own) { 23 final JTYPE result = pool.obtain(); 24 result.reset(cPtr, own); 25 return result; 26 } 27 /** delete the native object if required and allow the instance to be reused by the obtain method */ 28 public static void free(final JTYPE inst) { 29 inst.dispose(); 30 pool.free(inst); 31 } 32 %} 33 34 %fragment(gdxToString(gdxPooled##JTYPE), "header") { 35 // Inline (cached) method to retrieve the type's jclass 36 SWIGINTERN inline jclass &gdx_getClass##JTYPE(JNIEnv * const &jenv) { 37 static jclass cls = NULL; 38 if (cls == NULL) 39 cls = (jclass) jenv->NewGlobalRef(jenv->FindClass(gdxToString(_JCLASS))); 40 return cls; 41 } 42 43 // Inline method to get the termporary instance 44 SWIGINTERN inline jobject gdx_getTemp##JTYPE(JNIEnv * jenv, void *cPtr, bool ownMem) { 45 static jobject ret = NULL; 46 jclass &clazz = gdx_getClass##JTYPE(jenv); 47 if (ret == NULL) { 48 jfieldID field = jenv->GetStaticFieldID(clazz, "temp", gdxToString(L##_JCLASS##;)); 49 ret = jenv->NewGlobalRef(jenv->GetStaticObjectField(clazz, field)); 50 } 51 52 static jmethodID reuseMethod = NULL; 53 if (reuseMethod == NULL) 54 reuseMethod = (jmethodID) jenv->GetMethodID(clazz, "reset", "(JZ)V"); 55 56 long ptr; 57 *(const void **)&ptr = cPtr; 58 jenv->CallVoidMethod(ret, reuseMethod, ptr, (jboolean)ownMem); 59 return ret; 60 } 61 62 // Inline method to obtain an instance from the pool 63 SWIGINTERN inline jobject gdx_obtain##JTYPE(JNIEnv * jenv, jclass clazz, void *cPtr, bool ownMem) { 64 static jmethodID obtainMethod = NULL; 65 if (obtainMethod == NULL) 66 obtainMethod = (jmethodID) jenv->GetStaticMethodID(clazz, "obtain", gdxToString((JZ)L##_JCLASS##;)); 67 68 long ptr; 69 *(const void **)&ptr = cPtr; 70 jobject ret = jenv->CallStaticObjectMethod(clazz, obtainMethod, ptr, (jboolean)ownMem); 71 72 return ret; 73 } 74 75 // Inline method to free an instance from the pool 76 SWIGINTERN inline void gdx_free##JTYPE(JNIEnv * jenv, const jclass clazz, const jobject obj) { 77 static jmethodID freeMethod = NULL; 78 if (freeMethod == NULL) 79 freeMethod = (jmethodID) jenv->GetStaticMethodID(clazz, "free", gdxToString((L##_JCLASS##;)V)); 80 81 jenv->CallStaticVoidMethod(clazz, freeMethod, obj); 82 83 jenv->DeleteLocalRef(obj); 84 } 85 86 // Simple raii class to auto free the instance from the pool 87 class gdxAutoFree##JTYPE { 88 private: 89 JNIEnv * jenv; 90 jobject j##JTYPE; 91 jclass jclazz; 92 public: 93 gdxAutoFree##JTYPE(JNIEnv * jenv, jclass jclazz, jobject j##JTYPE) : 94 jenv(jenv), j##JTYPE(j##JTYPE), jclazz(jclazz) { } 95 virtual ~gdxAutoFree##JTYPE() { 96 gdx_free##JTYPE(this->jenv, this->jclazz, this->j##JTYPE); 97 } 98 }; 99 } 100 101 // The typemaps 102 %typemap(jni) CTYPE * "jlong" 103 %typemap(jtype) CTYPE * "long" 104 %typemap(jstype) CTYPE * "JTYPE" 105 %typemap(jni) CTYPE, CTYPE &, const CTYPE & "jobject" 106 %typemap(jstype) CTYPE, CTYPE &, const CTYPE & "JTYPE" 107 %typemap(jtype) CTYPE, CTYPE &, const CTYPE & "JTYPE" 108 %typemap(javain) CTYPE, CTYPE &, const CTYPE & "$javainput" 109 %typemap(javadirectorin) CTYPE, CTYPE &, const CTYPE & "$1" 110 %typemap(javadirectorout) CTYPE, CTYPE &, const CTYPE & "$javacall" 111 112 //%typemap(directorin, fragment=gdxToString(gdxPooled##JTYPE), descriptor=gdxToString(L##_JCLASS;), noblock=1) const CTYPE & { 113 // jclass jc$1 = gdx_getClass##JTYPE(jenv); 114 // $input = gdx_obtain##JTYPE(jenv, jc$1, (void*)$1, false); 115 // gdxAutoFree##JTYPE autoRelease_$input(jenv, jc$1, $input); 116 //} 117 %typemap(directorin, fragment=gdxToString(gdxPooled##JTYPE), descriptor=gdxToString(L##_JCLASS;), noblock=1) CTYPE, CTYPE &, const CTYPE & { 118 jclass jc$1 = gdx_getClass##JTYPE(jenv); 119 $input = gdx_obtain##JTYPE(jenv, jc$1, (void*)&$1, false); 120 gdxAutoFree##JTYPE autoRelease_$input(jenv, jc$1, $input); 121 } 122 %typemap(out, fragment=gdxToString(gdxPooled##JTYPE), noblock=1) CTYPE, CTYPE &, const CTYPE & { 123 $result = gdx_getTemp##JTYPE(jenv, &$1, false); 124 } 125 %typemap(javaout) CTYPE, CTYPE &, const CTYPE & { 126 return $jnicall; 127 } 128 %typemap(javaout) CTYPE * { 129 return JTYPE.internalTemp($jnicall, false); 130 } 131 132 %enddef // CREATE_POOLED_OBJECT_EXT 133 134 %define CREATE_POOLED_OBJECT(_TYPE, _JCLASS) 135 CREATE_POOLED_OBJECT_EXT(_TYPE, _TYPE, _JCLASS) 136 %enddef 137