MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
jtie_tconv_array_impl.hpp
1 /*
2  Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; version 2 of the License.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 /*
18  * jtie_tconv_array.hpp
19  */
20 
21 #ifndef jtie_tconv_array_impl_hpp
22 #define jtie_tconv_array_impl_hpp
23 
24 #include <assert.h> // not using namespaces yet
25 #include <jni.h>
26 
27 #include "jtie_tconv_value.hpp"
28 #include "jtie_tconv_value_impl.hpp"
29 #include "jtie_tconv_object_impl.hpp"
30 
31 // ---------------------------------------------------------------------------
32 // Utilities for Java array <-> C array type conversions
33 // ---------------------------------------------------------------------------
34 
45 template< typename JA,
46  typename CA >
47 struct ArrayConv {
69 #if 0 // disabled on purpose, only document function
70  static CA
71  getArrayElements(JNIEnv * env, JA j, jboolean * isCopy) {
72  TRACE("CA ArrayConv.getArrayElements(JNIEnv *, JA, jboolean *)");
73  (void)env; (void)j; (void)isCopy;
74  static_assert(false, "missing specialization of array conversion");
75  return 0;
76  }
77 #endif // disabled on purpose, only document function
78 
106 #if 0 // disabled on purpose, only document function
107  static void
108  releaseArrayElements(JNIEnv * env, JA j, const CA c, jint mode) {
109  TRACE("void ArrayConv.releaseArrayElements(JNIEnv *, JA, const CA, jint)");
110  (void)env; (void)j; (void)c; (void)mode;
111  static_assert(false, "missing specialization of array conversion");
112  return 0;
113  }
114 #endif // disabled on purpose, only document function
115 
136 #if 0 // disabled on purpose, only document function
137  static JA
138  newArray(JNIEnv * env, jsize len, const CA c) {
139  TRACE("JA ArrayConv.newArray(JNIEnv *, jsize, const CA)");
140  (void)env; (void)len; (void)c;
141  static_assert(false, "missing specialization of array conversion");
142  return 0;
143  }
144 #endif // disabled on purpose, only document function
145 };
146 
153 template< typename JA,
154  typename J,
155  typename C,
156  J * (JNIEnv::*GET)(JA, jboolean *),
157  void (JNIEnv::*REL)(JA, J *, jint),
158  JA (JNIEnv::*NEW)(jsize),
159  void (JNIEnv::*SET)(JA, jsize, jsize, const J *) >
161  static C *
162  getArrayElements(JNIEnv * env, JA j, jboolean * isCopy) {
163  TRACE("C * PrimArrayConvImpl.getArrayElements(JNIEnv *, JA, jboolean *)");
164  // XXX currently, only exact-width base type conversions supported
165  assert(sizeof(J) == sizeof(C));
166  assert(j != NULL);
167 
168  // init return value to error
169  C * c = NULL;
170 
171  J * ja = (env->*GET)(j, isCopy);
172  if (env->ExceptionCheck() != JNI_OK) {
173  // exception pending
174  } else {
175  // the JNI Spec (1.4..6) on Get<PrimitiveType>ArrayElements is
176  // not explicit on whether an exception has been registered
177  // when the operation returns NULL; so, better code defensively:
178  if (ja == NULL) {
179  const char * cl = "java/lang/AssertionError";
180  const char * m = ("JTie: a JNI Get<PrimitiveType>ArrayElements"
181  " function call returned NULL but has not"
182  " registered an exception with the VM"
183  " (file: " __FILE__ ")");
184  registerException(env, cl, m);
185  } else {
186  // ok, convert pointer types
187  c = reinterpret_cast< C * >(ja);
188  }
189  }
190  return c;
191  }
192 
193  static void
194  releaseArrayElements(JNIEnv * env, JA j, const C * c, jint mode) {
195  TRACE("void PrimArrayConvImpl.releaseArrayElements(JNIEnv *, JA, const C *, jint)");
196  // XXX currently, only exact-width base type conversions supported
197  assert(sizeof(J) == sizeof(C));
198  assert(j != NULL);
199  assert(c != NULL);
200 
201  if (c != NULL) {
202  // ok to strip const, pinned arrays are not changed by release
203  // and copies cannot be used after release
204  C * ca = const_cast< C * >(c);
205  // convert pointer types
206  (env->*REL)(j, reinterpret_cast< J * >(ca), mode);
207  }
208  }
209 
210  static JA
211  newArray(JNIEnv * env, jsize len, const C * c) {
212  TRACE("JA PrimArrayConvImpl.newArray(JNIEnv *, jsize, const C *)");
213  // XXX currently, only exact-width base type conversions supported
214  assert(sizeof(J) == sizeof(C));
215  assert(c != NULL);
216 
217  // init return value to error
218  JA j = NULL;
219 
220  JA ja = (env->*NEW)(len);
221  if (env->ExceptionCheck() != JNI_OK) {
222  // exception pending
223  } else {
224  // the JNI Spec (1.4..6) on New<PrimitiveType>Array is not
225  // explicit on whether an exception has been registered when the
226  // operation returns NULL; so, better code defensively:
227  if (ja == NULL) {
228  const char * cl = "java/lang/AssertionError";
229  const char * m = ("JTie: a JNI New<PrimitiveType>Array"
230  " function call returned NULL but has not"
231  " registered an exception with the VM"
232  " (file: " __FILE__ ")");
233  registerException(env, cl, m);
234  } else {
235  // convert pointer types
236  const J * cjc = reinterpret_cast< const J * >(c);
237 
238  // copy values to Java array
239  (env->*SET)(ja, 0, len, cjc);
240  if (env->ExceptionCheck() != JNI_OK) {
241  // exception pending
242  assert(false); // coding error: invalid index
243  } else {
244  // ok
245  j = ja;
246  }
247  }
248  }
249  return j;
250  }
251 
252 private:
254  // prohibit unsupported array type casts
255  is_valid_primitive_type_mapping< J, C >();
256  }
257 };
258 
280 template< typename J, typename C >
282  static C *
283  getArrayElements(JNIEnv * env, jobjectArray j, jboolean * isCopy) {
284  TRACE("C * ObjectArrayConvImpl.getArrayElements(JNIEnv *, jobjectArray, jboolean *)");
285  assert(j != NULL);
286 
287  // init return value to error
288  C * c = NULL;
289 
290  const jsize n = env->GetArrayLength(j);
291  if (env->ExceptionCheck() != JNI_OK) {
292  // exception pending
293  assert(false); // coding error: invalid argument
294  } else {
295  // ISO C++: 'new' throws std::bad_alloc if unsuccessful
296  C * ca = new C[n];
297 
298  cstatus s = copyToCObjectArray(ca, j, n, env);
299  if (s != 0) {
300  // exception pending
301  assert(env->ExceptionCheck() != JNI_OK);
302  delete[] ca;
303  } else {
304  // assign isCopy out parameter
305  if (isCopy != NULL) {
306  *isCopy
308  }
309 
310  // ok
311  c = ca;
312  }
313  }
314  return c;
315  }
316 
317  static void
318  releaseArrayElements(JNIEnv * env, jobjectArray j, const C * c, jint mode) {
319  TRACE("void ObjectArrayConvImpl.releaseArrayElements(JNIEnv *, jobjectArray, const C *, jint)");
320  assert(j != NULL);
321  assert(c != NULL);
322  delete[] c;
323  }
324 
325  static jobjectArray
326  newArray(JNIEnv * env, jsize len, const C * c) {
327  TRACE("jobjectArray ObjectArrayConvImpl.newArray(JNIEnv *, jsize, const C *)");
328  assert(c != NULL);
329 
330  // init return value to error
331  jobjectArray j = NULL;
332  jobjectArray ja = NULL;
333 
334  // get a (local or global) class object reference
335  jclass cls = ObjectResult< J *, C * >::J_ctor::getClass(env);
336  if (cls == NULL) {
337  // exception pending
338  } else {
339  J * ja = newJavaObjectArray(cls, len, env);
340  if (ja == NULL) {
341  // exception pending
342  } else {
343  cstatus s = copyToJavaObjectArray(ja, c, len, env);
344  if (s != 0) {
345  // exception pending
346  assert(env->ExceptionCheck() != JNI_OK);
347  } else {
348  // ok
349  j = ja;
350  }
351  }
352 
353  // release reference (if needed)
354  ObjectResult< J *, C * >::J_ctor::releaseRef(env, cls);
355  }
356  return j;
357  }
358 
359 private:
360  // Returns a new Java Object array with all elements initialized to null;
361  // in case of a NULL return, an exception is pending.
362  J *
363  newJavaObjectArray(jclass cls, jsize n, JNIEnv * env);
364 
365  // Copies objects referred by a Java Object array over a C object array;
366  // a non-zero return value indicates failure with an exception pending.
367  cstatus
368  copyToCObjectArray(C * c, jobjectArray j, jsize n, JNIEnv * env);
369 
370  // Initializes a Java Object array with references from a C object array;
371  // a non-zero return value indicates failure with an exception pending.
372  cstatus
373  copyToJavaObjectArray(jobjectArray j, C * c, jsize n, JNIEnv * env);
374 };
375 
376 template< typename J, typename C >
377 inline J *
379 newJavaObjectArray(jclass cls, jsize n, JNIEnv * env) {
380  assert(cls);
381 
382  // init return value to error
383  J * j = NULL;
384 
385  jobjectArray ja = env->NewObjectArray(n, cls, NULL);
386  if (env->ExceptionCheck() != JNI_OK) {
387  // exception pending
388  } else {
389  // the JNI Spec (1.4..6) on NewObjectArray is not explicit on
390  // whether an exception has been registered when the operation
391  // returns NULL; so, better code defensively:
392  if (ja == NULL) {
393  const char * cl = "java/lang/AssertionError";
394  const char * m = ("JTie: a JNI NewObjectArray function call"
395  " returned NULL but has not registered an"
396  " exception with the VM"
397  " (file: " __FILE__ ")");
398  registerException(env, cl, m);
399  } else {
400  // ok
401  j = ja;
402  }
403  }
404  return j;
405 }
406 
407 template< typename J, typename C >
408 inline cstatus
410 copyToCObjectArray(C * c, jobjectArray j, jsize n, JNIEnv * env) {
411  assert(j != NULL);
412  assert(c != NULL);
413 
414  // init return value to error
415  cstatus s = -1;
416 
417  // copy objects referenced from Java array to new array
418  jsize i;
419  for (i = 0; i < n; i++) {
420  // get the Java array element
421  _jobject * jfo = env->GetObjectArrayElement(j, i);
422  if (env->ExceptionCheck() != JNI_OK) {
423  // exception pending
424  assert(false); // coding error: invalid index
425  break;
426  }
427  assert(env->ExceptionCheck() == JNI_OK);
428 
429  // get the instance referenced by Java array element
430  _jtie_Object * jao = cast< _jtie_Object *, _jobject * >(jfo);
431  if (jao == NULL) {
432  const char * cl = "java/lang/IllegalArgumentException";
433  const char * m = ("JTie: the Java Object array must not have"
434  " null as elements when mapped to a"
435  " C object array (file: " __FILE__ ")");
436  registerException(env, cl, m);
437  break;
438  }
439  assert(jao != NULL);
440 
441  // get the C/C++ object referenced by Java array element
442  C * co = ObjectParam< _jtie_Object *, C * >::convert(s, jao, env);
443  assert(s != 0 || co != NULL);
444  if (s != 0) {
445  // exception pending
446  break;
447  }
448  assert(co != NULL);
449 
450  // copy referenced object to array element
451  // - copy-by-value semantics for Java only knows object references;
452  // - therefore, this mapping requires an accessible copy c'tor;
453  // - asymmetry to copyToCObjectArray()'s reference semantics
454  c[i] = *co;
455  }
456  if (i < n) {
457  // exception pending
458  } else {
459  // ok
460  s = 0;
461  }
462 
463  return c;
464 }
465 
466 template< typename J, typename C >
467 inline cstatus
469 copyToJavaObjectArray(jobjectArray j, C * c, jsize n, JNIEnv * env) {
470  assert(c != NULL);
471  assert(j != NULL);
472 
473  // init return value to error
474  cstatus s = -1;
475 
476  // copy C object references to Java array
477  jsize i;
478  for (i = 0; i < n; i++) {
479  // obtain reference to array element
480  // - no need for value-copy, would burden app's object management
481  // - asymmetry to copyToJavaObjectArray()'s value-copy semantics
482  C * co = c + i;
483 
484  // get a Java object reference
485  J * jao = ObjectResult< J *, C * >::convert(co, env);
486  if (jao == NULL) {
487  // exception pending
488  assert(env->ExceptionCheck() != JNI_OK);
489  break;
490  }
491  assert(jao != NULL);
492 
493  // set the Java array element
494  _jobject * jfo = cast< _jobject *, J * >(jao);
495  env->SetObjectArrayElement(j, i, jfo);
496  if (env->ExceptionCheck() != JNI_OK) {
497  // exception pending
498  assert(false); // coding error: invalid index or jao not subclass
499  break;
500  }
501  assert(env->ExceptionCheck() == JNI_OK);
502  }
503  if (i < n) {
504  // exception pending
505  } else {
506  // ok
507  s = 0;
508  }
509 
510  return c;
511 }
512 
513 // ---------------------------------------------------------------------------
514 // Specializations for array conversions
515 // ---------------------------------------------------------------------------
516 
517 // Avoid mapping types by broad, generic rules, which easily results in
518 // template instantiation ambiguities for non-primitive types. Therefore,
519 // we enumerate all specicializations for primitive types.
520 
521 // extend specializations to array of const
522 // Not sure why this generalized const specialization
523 // template< typename JA,
524 // typename CA >
525 // struct ArrayConv< JA, const CA > : ArrayConv< JA, CA > {};
526 // doesn't resolve (no effect); specializing individually for each type then.
527 
528 // specialize arrays conversion helper (for non-const and const)
529 #define JTIE_SPECIALIZE_ARRAY_TYPE_HELPER( JA, J, JN, C ) \
530  template<> \
531  struct ArrayConv< JA, C * > \
532  : PrimArrayConvImpl< JA, J, C, \
533  &JNIEnv::Get##JN##ArrayElements, \
534  &JNIEnv::Release##JN##ArrayElements, \
535  &JNIEnv::New##JN##Array, \
536  &JNIEnv::Set##JN##ArrayRegion > {}; \
537  template<> \
538  struct ArrayConv< JA, const C * > \
539  : ArrayConv< JA, C * > {};
540 
541 // ---------------------------------------------------------------------------
542 // Specializations for exact-width type array conversions
543 // ---------------------------------------------------------------------------
544 
545 JTIE_SPECIALIZE_ARRAY_TYPE_HELPER(jbooleanArray, jboolean, Boolean, bool)
546 
547 JTIE_SPECIALIZE_ARRAY_TYPE_HELPER(jbyteArray, jbyte, Byte, char)
548 JTIE_SPECIALIZE_ARRAY_TYPE_HELPER(jbyteArray, jbyte, Byte, signed char)
549 JTIE_SPECIALIZE_ARRAY_TYPE_HELPER(jbyteArray, jbyte, Byte, unsigned char)
550 
551 JTIE_SPECIALIZE_ARRAY_TYPE_HELPER(jfloatArray, jfloat, Float, float)
552 JTIE_SPECIALIZE_ARRAY_TYPE_HELPER(jdoubleArray, jdouble, Double, double)
553 
554 
555 // ---------------------------------------------------------------------------
556 // Specializations for variable-width type array conversions
557 // ---------------------------------------------------------------------------
558 
559 // jshort in LP32, ILP32, LP64, ILP64, LLP64
560 JTIE_SPECIALIZE_ARRAY_TYPE_HELPER(jshortArray, jshort, Short, signed short)
561 JTIE_SPECIALIZE_ARRAY_TYPE_HELPER(jshortArray, jshort, Short, unsigned short)
562 
563 // jshort in LP32
564 JTIE_SPECIALIZE_ARRAY_TYPE_HELPER(jshortArray, jshort, Short, signed int)
565 JTIE_SPECIALIZE_ARRAY_TYPE_HELPER(jshortArray, jshort, Short, unsigned int)
566 
567 // jint in ILP32, LP64, LLP64
568 JTIE_SPECIALIZE_ARRAY_TYPE_HELPER(jintArray, jint, Int, signed int)
569 JTIE_SPECIALIZE_ARRAY_TYPE_HELPER(jintArray, jint, Int, unsigned int)
570 
571 // jint in LP32, ILP32, LLP64
572 JTIE_SPECIALIZE_ARRAY_TYPE_HELPER(jintArray, jint, Int, signed long)
573 JTIE_SPECIALIZE_ARRAY_TYPE_HELPER(jintArray, jint, Int, unsigned long)
574 
575 // jlong in ILP64
576 JTIE_SPECIALIZE_ARRAY_TYPE_HELPER(jlongArray, jlong, Long, signed int)
577 JTIE_SPECIALIZE_ARRAY_TYPE_HELPER(jlongArray, jlong, Long, unsigned int)
578 
579 // jlong in LP64, ILP64
580 JTIE_SPECIALIZE_ARRAY_TYPE_HELPER(jlongArray, jlong, Long, signed long)
581 JTIE_SPECIALIZE_ARRAY_TYPE_HELPER(jlongArray, jlong, Long, unsigned long)
582 
583 // jlong in LLP64
584 JTIE_SPECIALIZE_ARRAY_TYPE_HELPER(jlongArray, jlong, Long, signed long long)
585 JTIE_SPECIALIZE_ARRAY_TYPE_HELPER(jlongArray, jlong, Long, unsigned long long)
586 
587 // jdouble
588 JTIE_SPECIALIZE_ARRAY_TYPE_HELPER(jdoubleArray, jdouble, Double, long double)
589 
590 // ---------------------------------------------------------------------------
591 
592 #endif // jtie_tconv_array_impl_hpp