読者です 読者をやめる 読者になる 読者になる

JNIですまぽみたいなの使いたい

JNI C++

はじめて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_;
    }
};