After some tinkering, I tried this for an STL-like container for JNI arrays. Tell me what you think:
// Emacs, this is -*- c++ -*- code. #ifndef JVECTOR_H_ #define JVECTOR_H_ #include <jni.h> #include <algorithm> #include <vector> #include <stdint.h> template<typename T> class jtype; /** * Base class with specializations to hide type differences in the JNI * API. * * XXX - handle exceptions (e.g., NULL return from NewArray). * * XXX - should switch to Get<Type>ArrayRegion and use a scroll window * ala SQL result sets. */ template<> struct jtype<jint> { typedef int32_t value_type; // jint == int32_t typedef jintArray array_type; mutable JNIEnv* env; explicit jtype (JNIEnv* env) : env (env) { } jtype (const jtype& that) : env (that.env) { } jtype& operator= (const jtype& that) { jtype tmp (that); swap (tmp); return *this; } ~jtype ( ) { env = 0; } /* * jsize (JNICALL *GetArrayLength) * (JNIEnv *env, jarray array); */ jsize GetArrayLength (jarray jarr) const { return env->GetArrayLength (jarr); } /* * jintArray (JNICALL *NewIntArray) * (JNIEnv *env, jsize len); */ array_type NewArray (jsize len) const { return env->NewIntArray (len); } /* * jint * (JNICALL *GetIntArrayElements) * (JNIEnv *env, jintArray array, jboolean *isCopy); */ value_type* GetArrayElements (array_type jarr, bool& is_copy) { jboolean b = is_copy ? JNI_TRUE : JNI_FALSE; value_type* arr = env->GetIntArrayElements (jarr, &b); is_copy = b == JNI_TRUE ? true : false; return arr; } value_type* GetArrayElements (array_type jarr) { return env->GetIntArrayElements (jarr, 0); } /* * void (JNICALL *ReleaseIntArrayElements) * (JNIEnv *env, jintArray array, jint *elems, jint mode); */ void ReleaseArrayElements (array_type jarr, value_type* arr, jint mode) { env->ReleaseIntArrayElements (jarr, arr, mode); } void ReleaseArrayElements (array_type jarr, value_type* arr) // 0 --> copy back and free element buffer { env->ReleaseIntArrayElements (jarr, arr, 0); } /* * void (JNICALL *GetIntArrayRegion) * (JNIEnv *env, jintArray array, jsize start, jsize len, jint buf); */ void GetArrayRegion (array_type jarr, jsize start, jsize len, value_type* arr) { env->GetIntArrayRegion (jarr, start, len, arr); } /* * void (JNICALL *SetIntArrayRegion) * (JNIEnv *env, jintArray array, jsize start, jsize len, const jint *buf); */ void SetArrayRegion (array_type jarr, jsize start, jsize len, const value_type* arr) // Not const. What gives? XXX { env->SetIntArrayRegion (jarr, start, len, const_cast<value_type*> (arr)); } void swap (jtype& that) throw ( ) { std::swap (env, that.env); } }; template<typename T> void std::swap (jtype<T>& lhs, jtype<T>& rhs) { lhs.swap (rhs); } /** * jvector<T> is an STL-like wrapper for Java arrays. Note that Java * arrays are immutable although the values can be changed. Therefore * operations like clear, resize, max_size, etc., make no sense are * are not included. */ template<typename T> class jvector : public jtype<T> { public: typedef typename jtype<T>::value_type value_type; typedef typename jtype<T>::array_type array_type; typedef value_type* pointer; typedef const value_type* const_pointer; typedef value_type& reference; typedef const value_type& const_reference; // Replace with checked versions. XXX typedef value_type* iterator; typedef const value_type* const_iterator; typedef jsize size_type; typedef std::ptrdiff_t difference_type; typedef std::reverse_iterator<const_iterator> const_reverse_iterator; typedef std::reverse_iterator<iterator> reverse_iterator; private: array_type jarr; size_type len; pointer arr; // XXX counted_arr<T> bool changed; public: jvector (JNIEnv* env, array_type jarr) : jtype<T> (env), jarr (jarr), len (GetArrayLength (jarr)), arr (GetArrayElements (jarr)), changed (false) { } jvector (const jvector& that) : jtype<T> (that), jarr (that.jarr), len (that.len), arr (that.arr), changed (that.changed) { } jvector operator= (const jvector& that) { jvector tmp (that); swap (tmp); return *this; } // Switching to a counted array for arr may remove the memory burden // on the JVM for the calls to {Get,Release}IntArrayElements past // the first one. XXX ~jvector ( ) { ReleaseArrayElements (jarr, arr, changed ? 0 : JNI_ABORT); } iterator begin ( ) { changed = true; return arr; } const_iterator begin ( ) const { return arr; } iterator end ( ) { changed = true; return arr + len; } const_iterator end ( ) const { return arr + len; } reverse_iterator rbegin ( ) { changed = true; return reverse_iterator (end ( )); } const_reverse_iterator rbegin ( ) const { return const_reverse_iterator (end ( )); } reverse_iterator rend ( ) { changed = true; return reverse_iterator (begin ( )); } const_reverse_iterator rend ( ) const { return const_reverse_iterator (begin ( )); } size_type size ( ) const { return size_type (end ( ) - begin ( )); } bool empty ( ) const { return begin ( ) == end ( ); } reference at (size_type n) { check_range (n); changed = true; return (*this)[n]; } const_reference at (size_type n) const { check_range (n); return (*this)[n]; } reference operator[](size_type n) { changed = true; return *(begin ( ) + n); } const_reference operator[](size_type n) const { return *(begin ( ) + n); } reference front ( ) { changed = true; return *begin ( ); } const_reference front ( ) const { return *begin ( ); } reference back ( ) { changed = true; return *(end ( ) - 1); } const_reference back ( ) const { return *(end ( ) - 1); } void swap (jvector& that) { std::swap (base, that.base); std::swap (jarr, that.jarr); std::swap (len, that.len); std::swap (arr, that.arr); std::swap (changed, that.changed); } private: void check_range (size_type n) const { if (n > len) throw std::out_of_range ("jvector"); } }; template<typename T> void std::swap (jvector<T>& lhs, jvector<T>& rhs) { lhs.swap (rhs); } #endif // JVECTOR_H_
No comments:
Post a Comment