1 #ifndef _java__cvc3__jni_utils_h_
2 #define _java__cvc3__jni_utils_h_
3 
4 #include <cassert>
5 #include <string>
6 #include <jni.h>
7 #include <typeinfo>
8 #include "vcl.h"
9 #include "hash_map.h"
10 #include "exception.h"
11 
12 namespace Java_cvc3_JniUtils {
13 
14   /// Embedding of c++ objects in java objects
15 
16   // generic delete function for any type T
17   template <class T> class DeleteEmbedded {
18   public:
deleteEmbedded(void * cobj)19     static void deleteEmbedded(void* cobj) {
20       delete (T*) cobj;
21     }
22   };
23 
24   typedef void (*TDeleteEmbedded)(void*);
25 
26 
27   // Encapsulates a c++ object so that:
28   // - (un)embedding casting is type safe
29   // - deallocation is automatic (if needed)
30   // This has probably quit a bit of overhead, because now for each
31   // wrapper object (even if only a temporary reference) an instance
32   // of Embedded is created.
33   // But considering the above two benefits it should be worth it
34   // because it should simplify maintenance quite a bit,
35   // as changes in the cvc API should lead to assertion failures
36   // instead of strange bugs.
37   class Embedded {
38   private:
39     // the actual embedded c++ object,
40     // as void* to make Embedded independent of its type
41     void* d_cobj;
42 
43     // the type info of d_cobj,
44     // to make sure that later unembeddings are type safe
45     // actually only needed in debugging, so might be guarded with IF_DEBUG
46     const std::type_info& d_typeInfo;
47 
48     // the type correct delete function for d_cobj,
49     // or NULL if this embedding is merely a reference
50     // and not responsible for its deallocation
51     TDeleteEmbedded d_delete;
52 
53   public:
Embedded(void * cobj,const std::type_info & ti,TDeleteEmbedded del)54     Embedded(void* cobj, const std::type_info& ti, TDeleteEmbedded del) :
55       d_cobj(cobj), d_typeInfo(ti), d_delete(del) {
56 	assert(d_cobj != NULL);
57     }
58 
~Embedded()59     ~Embedded() {
60       assert(d_cobj != NULL);
61       if (d_delete != NULL) d_delete(d_cobj);
62     }
63 
getCObj()64     const void* getCObj() const {
65       return d_cobj;
66     }
67 
getType()68     const std::type_info& getType() const {
69       return d_typeInfo;
70     }
71   };
72 
73 
74 
75   // embed functions
76 
77   // embeds a c++ object of type T into a jobject
78   // by first wrapping it into an Embedded object.
embed(JNIEnv * env,T * cobj,const std::type_info & ti,TDeleteEmbedded del)79   template <class T> jobject embed(JNIEnv* env, T* cobj, const std::type_info& ti,
80 				   TDeleteEmbedded del) {
81     DebugAssert(cobj != NULL, "JniUtils::embed: null object given");
82     Embedded* embedded = new Embedded((void*)cobj, ti, del);
83     return (jobject)env->NewDirectByteBuffer(embedded, sizeof(Embedded));
84   }
85 
86   // embeds a constant reference to a c++ object into a jobject
embed_const_ref(JNIEnv * env,const T * cobj)87   template <class T> jobject embed_const_ref(JNIEnv* env, const T* cobj) {
88     DebugAssert(cobj != NULL, "JniUtils::embed_const: null object given");
89     return embed<T>(env, (T*) cobj, typeid(cobj), NULL);
90   }
91 
92   // embeds a mutable reference to a c++ object into a jobject
embed_mut_ref(JNIEnv * env,T * cobj)93   template <class T> jobject embed_mut_ref(JNIEnv* env, T* cobj) {
94     DebugAssert(cobj != NULL, "JniUtils::embed_mut_ref: null object given");
95     return embed<T>(env, (T*) cobj, typeid(cobj), NULL);
96   }
97 
98   // embeds a fresh copy of a (probably temporary) c++ object into a jobject
embed_copy(JNIEnv * env,const T & cobj)99   template <class T> jobject embed_copy(JNIEnv* env, const T& cobj) {
100     DebugAssert(&cobj != NULL, "JniUtils::embed_copy: null object given");
101     T* copy = new T(cobj);
102     assert(copy != NULL);
103     return embed<T>(env, copy, typeid(copy), &DeleteEmbedded<T>::deleteEmbedded);
104   }
105 
106   // embeds a c++ object into a jobject,
107   // and takes over the responsibility to deallocate it
embed_own(JNIEnv * env,T * cobj)108   template <class T> jobject embed_own(JNIEnv* env, T* cobj) {
109     DebugAssert(&cobj != NULL, "JniUtils::embed_own: null object given");
110     return embed<T>(env, cobj, typeid(cobj), &DeleteEmbedded<T>::deleteEmbedded);
111   }
112 
113 
114   // unembed functions
115 
116   // extract Embedded* from a jobject
117   Embedded* unembed(JNIEnv* env, jobject jobj);
118 
119   // extract a constant c++ object of type T from a jobject
unembed_const(JNIEnv * env,jobject jobj)120   template <class T> const T* unembed_const(JNIEnv* env, jobject jobj) {
121     Embedded* embedded = unembed(env, jobj);
122     return (const T*) embedded->getCObj();
123   }
124 
125   // extract a mutable c++ object of type T from a jobject
unembed_mut(JNIEnv * env,jobject jobj)126   template <class T> T* unembed_mut(JNIEnv* env, jobject jobj) {
127     Embedded* embedded = unembed(env, jobj);
128     // check that the wrapped object is not const
129     DebugAssert(embedded->getType() == typeid(T*),
130 		"JniUtils::unembed_mut: type mismatch");
131     return (T*) embedded->getCObj();
132   }
133 
134 
135   // delete embedded
136 
137   // delete the Embedded object contained in a jobject,
138   // and also destruct the wrapped c++ object if necessary.
139   void deleteEmbedded(JNIEnv* env, jobject jobj);
140 
141 
142 
143 
144   /// Conversions between c++ and java
145 
146   // bool
147   bool toCpp(jboolean j);
148 
149   // string
150   jstring toJava(JNIEnv* env, const std::string& cstring);
151   jstring toJava(JNIEnv* env, const char* cstring);
152   std::string toCpp(JNIEnv* env, const jstring& string);
153 
154   // enums
155   jstring toJava(JNIEnv* env, CVC3::QueryResult result);
156   jstring toJava(JNIEnv* env, CVC3::FormulaValue result);
157   jstring toJava(JNIEnv* env, CVC3::InputLanguage result);
158   CVC3::InputLanguage toCppInputLanguage(JNIEnv* env, const std::string& lang);
159 
160   // exceptions
161   void toJava(JNIEnv* env, const CVC3::Exception& e);
162 
163   // vectors
toJavaVCopy(JNIEnv * env,const std::vector<T> & v)164   template <class T> jobjectArray toJavaVCopy(JNIEnv* env, const std::vector<T>& v) {
165     jobjectArray jarray = (jobjectArray)
166       env->NewObjectArray(
167 	v.size(),
168 	env->FindClass("java/lang/Object"),
169 	NULL);
170 
171     for (int i = 0; i < v.size(); ++i) {
172       env->SetObjectArrayElement(jarray, i, embed_copy<T>(env, v[i]));
173     }
174 
175     return jarray;
176   }
177 
toJavaVConstRef(JNIEnv * env,const std::vector<T> & v)178   template <class T> jobjectArray toJavaVConstRef(JNIEnv* env, const std::vector<T>& v) {
179     jobjectArray jarray = (jobjectArray)
180       env->NewObjectArray(
181 	v.size(),
182 	env->FindClass("java/lang/Object"),
183 	NULL);
184 
185     for (int i = 0; i < v.size(); ++i) {
186       env->SetObjectArrayElement(jarray, i, embed_const_ref<T>(env, &v[i]));
187     }
188 
189     return jarray;
190   }
191 
192   template<class T>
193     jobjectArray
toJavaVVConstRef(JNIEnv * env,const std::vector<std::vector<T>> & v)194     toJavaVVConstRef(JNIEnv* env, const std::vector<std::vector<T> >& v)
195     {
196       jobjectArray jarray = (jobjectArray) env->NewObjectArray(v.size(),
197           env->FindClass("[Ljava/lang/Object;"), NULL);
198       for (int i = 0; i < v.size(); ++i)
199         {
200           env->SetObjectArrayElement(jarray, i, toJavaVConstRef(env, v[i]));
201         }
202       return jarray;
203     }
204 
toCppV(JNIEnv * env,const jobjectArray & jarray)205   template <class T> std::vector<T> toCppV(JNIEnv* env, const jobjectArray& jarray) {
206     std::vector<T> v;
207     int length = env->GetArrayLength(jarray);
208     for (int i = 0; i < length; ++i) {
209       v.push_back(*unembed_const<T>(env, env->GetObjectArrayElement(jarray, i)));
210     }
211     return v;
212   }
213 
toCppVV(JNIEnv * env,const jobjectArray & jarray)214   template <class T> std::vector<std::vector<T> > toCppVV(JNIEnv* env, const jobjectArray& jarray) {
215     std::vector<std::vector<T> > v;
216     int length = env->GetArrayLength(jarray);
217     for (int i = 0; i < length; ++i) {
218       jobjectArray jsub = static_cast<jobjectArray>(env->GetObjectArrayElement(jarray, i));
219       v.push_back(toCppV<T>(env, jsub));
220     }
221     return v;
222   }
223 
224   template <class T> std::vector<std::vector<std::vector<T> > >
toCppVVV(JNIEnv * env,const jobjectArray & jarray)225     toCppVVV(JNIEnv* env, const jobjectArray& jarray) {
226     std::vector<std::vector<std::vector<T> > > v;
227     int length = env->GetArrayLength(jarray);
228     for (int i = 0; i < length; ++i) {
229       jobjectArray jsub = static_cast<jobjectArray>(env->GetObjectArrayElement(jarray, i));
230       v.push_back(toCppVV<T>(env, jsub));
231     }
232     return v;
233   }
234 
235   // string vectors
236   std::vector<std::string> toCppV(JNIEnv* env, const jobjectArray& jarray);
237   std::vector<std::vector<std::string> > toCppVV(JNIEnv* env, const jobjectArray& jarray);
238   std::vector<std::vector<std::vector<std::string> > > toCppVVV(JNIEnv* env, const jobjectArray& jarray);
239   jobjectArray toJavaV(JNIEnv* env, const std::vector<std::string>& v);
240 
241   // primitive vectors
242   std::vector<bool> toCppV(JNIEnv* env, const jbooleanArray& jarray);
243 
244 
245   // hash map
toJavaHCopy(JNIEnv * env,const Hash::hash_map<K,V> & hm)246   template <class K, class V> jobjectArray toJavaHCopy(JNIEnv* env, const Hash::hash_map<K, V>& hm) {
247     jobjectArray jarray = (jobjectArray)
248       env->NewObjectArray(
249 	hm.size() * 2,
250 	env->FindClass("java/lang/Object"),
251 	NULL);
252 
253     int i = 0;
254     typename Hash::hash_map<K, V>::const_iterator it;
255     for (it = hm.begin(); it != hm.end(); ++it) {
256       assert(i < env->GetArrayLength(jarray));
257       env->SetObjectArrayElement(jarray, i, embed_copy<K>(env, it->first));
258       ++i;
259       assert(i < env->GetArrayLength(jarray));
260       env->SetObjectArrayElement(jarray, i, embed_copy<V>(env, it->second));
261       ++i;
262     }
263     return jarray;
264   }
265 
toJavaHCopy(JNIEnv * env,const CVC3::ExprMap<V> & hm)266   template <class V> jobjectArray toJavaHCopy(JNIEnv* env, const CVC3::ExprMap<V>& hm) {
267     jobjectArray jarray = (jobjectArray)
268       env->NewObjectArray(
269 	hm.size() * 2,
270 	env->FindClass("java/lang/Object"),
271 	NULL);
272 
273     int i = 0;
274     typename CVC3::ExprMap<V>::const_iterator it;
275     for (it = hm.begin(); it != hm.end(); ++it) {
276       assert(i < env->GetArrayLength(jarray));
277       env->SetObjectArrayElement(jarray, i, embed_copy<CVC3::Expr>(env, it->first));
278       ++i;
279       assert(i < env->GetArrayLength(jarray));
280       env->SetObjectArrayElement(jarray, i, embed_copy<V>(env, it->second));
281       ++i;
282     }
283     return jarray;
284   }
285 
286 }
287 
288 
289 #endif
290