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