JNIですまぽみたいなの使いたい
はじめてJNIのコード書いていて、すまぽ欲しいよねこれと思ったのでちょこっと書いてみた。
こんな感じ。
static void throw_IndexOutOfBoundsException(JNIEnv *env, char const * const message); template <typename T> class safe_array { private: JNIEnv *env_; jarray const &array_; T* ptr_; size_t size_; bool is_copy_; bool is_aborted_; T dummy_; public: safe_array(JNIEnv *env, jarray const &array) : env_(env), array_(array), ptr_(NULL), size_(0), is_copy_(false), is_aborted_(false), dummy_(0) { jboolean is_copy = JNI_FALSE; ptr_ = static_cast<T*>(env->GetPrimitiveArrayCritical(array, &is_copy)); size_ = env->GetArrayLength(array); is_copy_ = (JNI_FALSE == is_copy) ? false : true; } ~safe_array() { if (is_aborted_) { env_->ReleasePrimitiveArrayCritical(array_, ptr_, JNI_ABORT); } else { env_->ReleasePrimitiveArrayCritical(array_, ptr_, is_copy_ ? JNI_COMMIT : 0); } } T& operator[] (int const &index) { if ((index < 0) || ((size_t)index >= size_)) { throw_IndexOutOfBoundsException(env_, "Index out of bounds"); return dummy_; } return ptr_[index]; } T const& operator[] (int const &index) const { if ((index < 0) || ((size_t)index >= size_)) { throw_IndexOutOfBoundsException(env_, "Index out of bounds"); return dummy_; } return ptr_[index]; } T* get() { return ptr_; } T const *get() const { return ptr_; } size_t size() const { return size_; } void abort() const { is_aborted_ = true; } bool is_copy() const { return is_copy_; } bool is_aborted() const { return is_aborted_; } };
jarrayを中でポインタに変換したまま保持するやつ。
本当はconstructorをjarrayで受けるんじゃなくて、元の型(jbyteArrayとか)で受けて型安全にするべきなんだけど、時間がなかったので手抜き。
Androidはなんかよく知らないけどもGetPrimitiveArrayCriticalやるとコピーが発生しなくて早いとかなんとかって話らしい(要出典)ので、こんな実装。
C++のexception使おうとしたらlinkの関係で怒られたので渋々こんな実装になっている。dummyを返すとかあほらしいことしたくないでござる。
あとはこんなのとか。
template <typename T> class safe_local_ref { private: JNIEnv *env_; T ref_; public: safe_local_ref(JNIEnv *env, T obj) : env_(env), ref_(obj) { } ~safe_local_ref() { env_->DeleteLocalRef(ref_); } T get() const { return ref_; } bool operator == (T &opr) const { return ref_ == opr; } bool operator != (T &opr) const { return ref_ != opr; } bool operator ! () const { return !ref_; } friend bool operator == (T left, safe_local_ref<T> const &right) { return left == right.ref_; } friend bool operator != (T left, safe_local_ref<T> const &right) { return left != right.ref_; } };