Merge "Revert "Rewrite scoped arrays with template and introduced nullable one.""
am: 9042585fa0

Change-Id: Ide0f0b5580ded28c962aa68b215abc9744d359fd
diff --git a/header_only_include/nativehelper/scoped_primitive_array.h b/header_only_include/nativehelper/scoped_primitive_array.h
index 17f18a3..d6840c2 100644
--- a/header_only_include/nativehelper/scoped_primitive_array.h
+++ b/header_only_include/nativehelper/scoped_primitive_array.h
@@ -17,10 +17,6 @@
 #ifndef SCOPED_PRIMITIVE_ARRAY_H_
 #define SCOPED_PRIMITIVE_ARRAY_H_
 
-#include <type_traits>
-
-#include <sys/types.h>  // For ssize_t
-
 #include "jni.h"
 #include "nativehelper_utils.h"
 
@@ -30,184 +26,122 @@
 #define POINTER_TYPE(T) T*  /* NOLINT */
 #endif
 
-template<typename JType> struct ScopedPrimitiveArrayTraits {};
+#ifdef REFERENCE_TYPE
+#error REFERENCE_TYPE is defined.
+#else
+#define REFERENCE_TYPE(T) T&  /* NOLINT */
+#endif
 
-#define ARRAY_TRAITS(ARRAY_TYPE, JTYPE, NAME)                                            \
-template<> struct ScopedPrimitiveArrayTraits<JTYPE> {                                    \
-public:                                                                                  \
-    static inline void getArrayRegion(JNIEnv* env, ARRAY_TYPE array, size_t start,       \
-                                      size_t len, POINTER_TYPE(JTYPE) out) {             \
-        env->Get ## NAME ## ArrayRegion(array, start, len, out);                         \
-    }                                                                                    \
-                                                                                         \
-    static inline POINTER_TYPE(JTYPE) getArrayElements(JNIEnv* env, ARRAY_TYPE array) {  \
-        return env->Get ## NAME ## ArrayElements(array, nullptr);                        \
-    }                                                                                    \
-                                                                                         \
-    static inline void releaseArrayElements(JNIEnv* env, ARRAY_TYPE array,               \
-                                            POINTER_TYPE(JTYPE) buffer, jint mode) {     \
-        env->Release ## NAME ## ArrayElements(array, buffer, mode);                      \
-    }                                                                                    \
-    static inline size_t getArrayLength(JNIEnv* env, ARRAY_TYPE array) {                 \
-        return env->GetArrayLength(array);                                               \
-    }                                                                                    \
-    static inline void fatalError(JNIEnv* env, const char*msg) {                         \
-        env->FatalError(msg);                                                            \
-    }                                                                                    \
-    using ArrayType = ARRAY_TYPE;                                                        \
-};                                                                                       \
+// ScopedBooleanArrayRO, ScopedByteArrayRO, ScopedCharArrayRO, ScopedDoubleArrayRO,
+// ScopedFloatArrayRO, ScopedIntArrayRO, ScopedLongArrayRO, and ScopedShortArrayRO provide
+// convenient read-only access to Java arrays from JNI code. This is cheaper than read-write
+// access and should be used by default.
+#define INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(PRIMITIVE_TYPE, NAME) \
+    class Scoped ## NAME ## ArrayRO { \
+    public: \
+        explicit Scoped ## NAME ## ArrayRO(JNIEnv* env) \
+        : mEnv(env), mJavaArray(NULL), mRawArray(NULL), mSize(0) {} \
+        Scoped ## NAME ## ArrayRO(JNIEnv* env, PRIMITIVE_TYPE ## Array javaArray) \
+        : mEnv(env) { \
+            if (javaArray == NULL) { \
+                mJavaArray = NULL; \
+                mSize = 0; \
+                mRawArray = NULL; \
+                jniThrowNullPointerException(mEnv, NULL); \
+            } else { \
+                reset(javaArray); \
+            } \
+        } \
+        ~Scoped ## NAME ## ArrayRO() { \
+            if (mRawArray != NULL && mRawArray != mBuffer) { \
+                mEnv->Release ## NAME ## ArrayElements(mJavaArray, mRawArray, JNI_ABORT); \
+            } \
+        } \
+        void reset(PRIMITIVE_TYPE ## Array javaArray) { \
+            mJavaArray = javaArray; \
+            mSize = mEnv->GetArrayLength(mJavaArray); \
+            if (mSize <= buffer_size) { \
+                mEnv->Get ## NAME ## ArrayRegion(mJavaArray, 0, mSize, mBuffer); \
+                mRawArray = mBuffer; \
+            } else { \
+                mRawArray = mEnv->Get ## NAME ## ArrayElements(mJavaArray, NULL); \
+            } \
+        } \
+        const PRIMITIVE_TYPE* get() const { return mRawArray; } \
+        PRIMITIVE_TYPE ## Array getJavaArray() const { return mJavaArray; } \
+        const PRIMITIVE_TYPE& operator[](size_t n) const { return mRawArray[n]; } \
+        size_t size() const { return mSize; } \
+    private: \
+        static const jsize buffer_size = 1024; \
+        JNIEnv* const mEnv; \
+        PRIMITIVE_TYPE ## Array mJavaArray; \
+        POINTER_TYPE(PRIMITIVE_TYPE) mRawArray; \
+        jsize mSize; \
+        PRIMITIVE_TYPE mBuffer[buffer_size]; \
+        DISALLOW_COPY_AND_ASSIGN(Scoped ## NAME ## ArrayRO); \
+    }
 
-ARRAY_TRAITS(jbooleanArray, jboolean, Boolean)
-ARRAY_TRAITS(jbyteArray, jbyte, Byte)
-ARRAY_TRAITS(jcharArray, jchar, Char)
-ARRAY_TRAITS(jdoubleArray, jdouble, Double)
-ARRAY_TRAITS(jfloatArray, jfloat, Float)
-ARRAY_TRAITS(jintArray, jint, Int)
-ARRAY_TRAITS(jlongArray, jlong, Long)
-ARRAY_TRAITS(jshortArray, jshort, Short)
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jboolean, Boolean);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jbyte, Byte);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jchar, Char);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jdouble, Double);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jfloat, Float);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jint, Int);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jlong, Long);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jshort, Short);
 
-#undef ARRAY_TRAITS
+#undef INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO
+
+// ScopedBooleanArrayRW, ScopedByteArrayRW, ScopedCharArrayRW, ScopedDoubleArrayRW,
+// ScopedFloatArrayRW, ScopedIntArrayRW, ScopedLongArrayRW, and ScopedShortArrayRW provide
+// convenient read-write access to Java arrays from JNI code. These are more expensive,
+// since they entail a copy back onto the Java heap, and should only be used when necessary.
+#define INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(PRIMITIVE_TYPE, NAME) \
+    class Scoped ## NAME ## ArrayRW { \
+    public: \
+        explicit Scoped ## NAME ## ArrayRW(JNIEnv* env) \
+        : mEnv(env), mJavaArray(NULL), mRawArray(NULL) {} \
+        Scoped ## NAME ## ArrayRW(JNIEnv* env, PRIMITIVE_TYPE ## Array javaArray) \
+        : mEnv(env), mJavaArray(javaArray), mRawArray(NULL) { \
+            if (mJavaArray == NULL) { \
+                jniThrowNullPointerException(mEnv, NULL); \
+            } else { \
+                mRawArray = mEnv->Get ## NAME ## ArrayElements(mJavaArray, NULL); \
+            } \
+        } \
+        ~Scoped ## NAME ## ArrayRW() { \
+            if (mRawArray) { \
+                mEnv->Release ## NAME ## ArrayElements(mJavaArray, mRawArray, 0); \
+            } \
+        } \
+        void reset(PRIMITIVE_TYPE ## Array javaArray) { \
+            mJavaArray = javaArray; \
+            mRawArray = mEnv->Get ## NAME ## ArrayElements(mJavaArray, NULL); \
+        } \
+        const PRIMITIVE_TYPE* get() const { return mRawArray; } \
+        PRIMITIVE_TYPE ## Array getJavaArray() const { return mJavaArray; } \
+        const PRIMITIVE_TYPE& operator[](size_t n) const { return mRawArray[n]; } \
+        POINTER_TYPE(PRIMITIVE_TYPE) get() { return mRawArray; }  \
+        REFERENCE_TYPE(PRIMITIVE_TYPE) operator[](size_t n) { return mRawArray[n]; } \
+        size_t size() const { return mEnv->GetArrayLength(mJavaArray); } \
+    private: \
+        JNIEnv* const mEnv; \
+        PRIMITIVE_TYPE ## Array mJavaArray; \
+        POINTER_TYPE(PRIMITIVE_TYPE) mRawArray; \
+        DISALLOW_COPY_AND_ASSIGN(Scoped ## NAME ## ArrayRW); \
+    }
+
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jboolean, Boolean);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jbyte, Byte);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jchar, Char);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jdouble, Double);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jfloat, Float);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jint, Int);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jlong, Long);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jshort, Short);
+
+#undef INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW
 #undef POINTER_TYPE
-
-template<typename JType, bool kNullable>
-class ScopedArrayRO {
-public:
-    using Traits = ScopedPrimitiveArrayTraits<JType>;
-    using ArrayType = typename Traits::ArrayType;
-    using const_iterator = const JType*;
-
-    // Provides read-only access to Java array from JNI code.
-    // env must not be nullptr.
-    // If kNullable is false, this aborts if javaArray is nullptr.
-    ScopedArrayRO(JNIEnv* env, ArrayType javaArray) : mEnv(env), mJavaArray(javaArray) {
-        if (mJavaArray == nullptr) {
-            mSize = -1;
-            mRawArray = nullptr;
-            if (!kNullable) {
-                Traits::fatalError(mEnv, "javaArray is null");
-            }
-        } else {
-            mSize = Traits::getArrayLength(mEnv, mJavaArray);
-            if (mSize <= BUFFER_SIZE) {
-                Traits::getArrayRegion(mEnv, mJavaArray, 0, mSize, mBuffer);
-                mRawArray = mBuffer;
-            } else {
-                mRawArray = Traits::getArrayElements(mEnv, mJavaArray);
-            }
-        }
-    }
-
-    ~ScopedArrayRO() {
-        if (mRawArray != nullptr && mRawArray != mBuffer) {
-            Traits::releaseArrayElements(mEnv, mJavaArray, mRawArray, JNI_ABORT);
-        }
-    }
-
-    const JType* get() const { return mRawArray; }
-    ArrayType getJavaArray() const { return mJavaArray; }
-    const JType& operator[](size_t n) const { return mRawArray[n]; }
-    const_iterator begin() const { return get(); }
-    const_iterator end() const {
-        return (kNullable && mRawArray == nullptr) ? get() : get() + mSize;
-    }
-
-    using SizeT = typename std::conditional<kNullable, ssize_t, size_t>::type;
-    // In case of nonnull array, the return type is size_t.
-    // In case of nullable array, the return type is ssize_t. Then, will return -1 if this is
-    // constructed with null array.
-    SizeT size() const { return mSize; }
-
-private:
-    // 1024 since there is stack frame size limitation (4096 bytes).
-    constexpr static jsize BUFFER_SIZE = 1024 / sizeof(JType);
-
-    JNIEnv* const mEnv;
-    ArrayType mJavaArray;
-    JType* mRawArray;
-    SizeT mSize;
-
-    // Speed-up JNI array access for small arrays, see I703d7346de732199be1feadbead021c6647a554a
-    // for more details.
-    JType mBuffer[BUFFER_SIZE];
-
-    DISALLOW_COPY_AND_ASSIGN(ScopedArrayRO);
-};
-
-// Scoped***ArrayRO provide convenient read-only access to Java array from JNI code.
-// This is cheaper than read-write access and should be used by default.
-// These abort if nullptr is passed.
-using ScopedBooleanArrayRO = ScopedArrayRO<jboolean, false>;
-using ScopedByteArrayRO = ScopedArrayRO<jbyte, false>;
-using ScopedCharArrayRO = ScopedArrayRO<jchar, false>;
-using ScopedDoubleArrayRO = ScopedArrayRO<jdouble, false>;
-using ScopedFloatArrayRO = ScopedArrayRO<jfloat, false>;
-using ScopedIntArrayRO = ScopedArrayRO<jint, false>;
-using ScopedLongArrayRO = ScopedArrayRO<jlong, false>;
-using ScopedShortArrayRO = ScopedArrayRO<jshort, false>;
-
-// ScopedNullable***ArrayRO also provide convenient read-only access to Java array from JNI code.
-// These accept nullptr. In that case, get() returns nullptr and size() returns -1.
-using ScopedNullableBooleanArrayRO = ScopedArrayRO<jboolean, true>;
-using ScopedNullableByteArrayRO = ScopedArrayRO<jbyte, true>;
-using ScopedNullableCharArrayRO = ScopedArrayRO<jchar, true>;
-using ScopedNullableDoubleArrayRO = ScopedArrayRO<jdouble, true>;
-using ScopedNullableFloatArrayRO = ScopedArrayRO<jfloat, true>;
-using ScopedNullableIntArrayRO = ScopedArrayRO<jint, true>;
-using ScopedNullableLongArrayRO = ScopedArrayRO<jlong, true>;
-using ScopedNullableShortArrayRO = ScopedArrayRO<jshort, true>;
-
-template<typename JType>
-class ScopedArrayRW {
-public:
-    using Traits = ScopedPrimitiveArrayTraits<JType>;
-    using ArrayType = typename Traits::ArrayType;
-    using const_iterator = const JType*;
-    using iterator = JType*;
-
-    ScopedArrayRW(JNIEnv* env, ArrayType javaArray) : mEnv(env), mJavaArray(javaArray) {
-        if (mJavaArray == nullptr) {
-            Traits::fatalError(mEnv, "javaArray is null");
-        } else {
-            mSize = Traits::getArrayLength(mEnv, mJavaArray);
-            mRawArray = Traits::getArrayElements(mEnv, mJavaArray);
-        }
-    }
-    ~ScopedArrayRW() {
-        if (mRawArray != nullptr) {
-            Traits::releaseArrayElements(mEnv, mJavaArray, mRawArray, 0);
-        }
-    }
-
-    const JType* get() const { return mRawArray; }
-    ArrayType getJavaArray() const { return mJavaArray; }
-    const JType& operator[](size_t n) const { return mRawArray[n]; }
-    const_iterator cbegin() const { return get(); }
-    const_iterator cend() const { return get() + mSize; }
-    JType* get() { return mRawArray; }
-    JType& operator[](size_t n) { return mRawArray[n]; }
-    iterator begin() { return get(); }
-    iterator end() { return get() + mSize; }
-    size_t size() const { return mSize; }
-
-private:
-    JNIEnv* const mEnv;
-    ArrayType mJavaArray;
-    JType* mRawArray;
-    jsize mSize;
-    DISALLOW_COPY_AND_ASSIGN(ScopedArrayRW);
-};
-
-// Scoped***ArrayRW provide convenient read-write access to Java arrays from JNI code.
-// These are more expensive, since they entail a copy back onto the Java heap, and should only be
-// used when necessary.
-// These abort if nullptr is passed.
-using ScopedBooleanArrayRW = ScopedArrayRW<jboolean>;
-using ScopedByteArrayRW = ScopedArrayRW<jbyte>;
-using ScopedCharArrayRW = ScopedArrayRW<jchar>;
-using ScopedDoubleArrayRW = ScopedArrayRW<jdouble>;
-using ScopedFloatArrayRW = ScopedArrayRW<jfloat>;
-using ScopedIntArrayRW = ScopedArrayRW<jint>;
-using ScopedLongArrayRW = ScopedArrayRW<jlong>;
-using ScopedShortArrayRW = ScopedArrayRW<jshort>;
+#undef REFERENCE_TYPE
 
 #endif  // SCOPED_PRIMITIVE_ARRAY_H_
diff --git a/tests/Android.bp b/tests/Android.bp
index d30b4d2..e6cbf5c 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -4,10 +4,7 @@
     name: "JniInvocation_test",
     test_suites: ["device-tests"],
     host_supported: true,
-    srcs: [
-        "JniInvocation_test.cpp",
-        "scoped_primitive_array_test.cpp"
-    ],
+    srcs: ["JniInvocation_test.cpp"],
     cflags: ["-Wall", "-Werror"],
     shared_libs: ["libnativehelper"],
 }
diff --git a/tests/scoped_primitive_array_test.cpp b/tests/scoped_primitive_array_test.cpp
deleted file mode 100644
index cba258c..0000000
--- a/tests/scoped_primitive_array_test.cpp
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <nativehelper/scoped_primitive_array.h>
-
-#include <gtest/gtest.h>
-
-struct TestType { char dummy[1]; };
-using jTestTypeArray = void*;
-
-const jTestTypeArray LARGE_ARRAY = reinterpret_cast<jTestTypeArray>(0x1);
-const jTestTypeArray SMALL_ARRAY = reinterpret_cast<jTestTypeArray>(0x2);
-
-constexpr size_t LARGE_ARRAY_SIZE = 8192;
-constexpr size_t SMALL_ARRAY_SIZE = 32;
-
-struct TestContext {
-    TestType* dummyPtr;
-
-    int getArrayElementsCallCount = 0;
-    int releaseArrayElementsCallCount = 0;
-    bool aborted = false;
-    bool elementsUpdated = false;
-
-    void resetCallCount() {
-        getArrayElementsCallCount = 0;
-        releaseArrayElementsCallCount = 0;
-        aborted = false;
-        elementsUpdated = false;
-    }
-
-    bool memoryUpdated() const {
-        return releaseArrayElementsCallCount > 0 && elementsUpdated;
-    }
-};
-
-// Mock implementation of the ScopedPrimitiveArrayTraits.
-// JNIEnv is abused for passing TestContext.
-template<> struct ScopedPrimitiveArrayTraits<TestType> {
-public:
-    static inline void getArrayRegion(JNIEnv*, jTestTypeArray, size_t, size_t, TestType*) {}
-
-    static inline TestType* getArrayElements(JNIEnv* env, jTestTypeArray) {
-        TestContext* ctx = reinterpret_cast<TestContext*>(env);
-        ctx->getArrayElementsCallCount++;
-        return ctx->dummyPtr;
-    }
-
-    static inline void releaseArrayElements(JNIEnv* env, jTestTypeArray, TestType* buffer,
-                                            jint mode) {
-        TestContext* ctx = reinterpret_cast<TestContext*>(env);
-        if (ctx->dummyPtr == buffer) {
-            ctx->releaseArrayElementsCallCount++;
-        }
-        ctx->elementsUpdated = (mode != JNI_ABORT);
-    }
-
-    static inline size_t getArrayLength(JNIEnv*, jTestTypeArray array) {
-        return array == LARGE_ARRAY ? LARGE_ARRAY_SIZE : SMALL_ARRAY_SIZE;
-    }
-
-    static inline void fatalError(JNIEnv* env, const char*) {
-        reinterpret_cast<TestContext*>(env)->aborted = true;
-    }
-
-    using ArrayType = jTestTypeArray;
-};
-
-TEST(ScopedPrimitiveArrayTest, testNonNullArray) {
-    std::unique_ptr<TestType[]> dummyTestType = std::make_unique<TestType[]>(LARGE_ARRAY_SIZE);
-
-    TestContext context;
-    context.dummyPtr = dummyTestType.get();
-
-    JNIEnv* env = reinterpret_cast<JNIEnv*>(&context);
-    {
-        context.resetCallCount();
-        {
-            ScopedArrayRO<TestType, false /* non null */> array(env, SMALL_ARRAY);
-            EXPECT_NE(nullptr, array.get());
-            EXPECT_EQ(SMALL_ARRAY, array.getJavaArray());
-            EXPECT_NE(nullptr, array.begin());
-            EXPECT_NE(nullptr, array.end());
-            EXPECT_EQ(array.end(), array.begin() + SMALL_ARRAY_SIZE);
-            EXPECT_EQ(SMALL_ARRAY_SIZE, array.size());
-        }
-        EXPECT_EQ(context.getArrayElementsCallCount, context.releaseArrayElementsCallCount);
-        EXPECT_FALSE(context.memoryUpdated());
-        EXPECT_FALSE(context.aborted);
-    }
-    {
-        context.resetCallCount();
-        {
-            ScopedArrayRO<TestType, false /* non null */> array(env, LARGE_ARRAY);
-
-            EXPECT_EQ(context.dummyPtr, array.get());
-            EXPECT_EQ(LARGE_ARRAY, array.getJavaArray());
-            EXPECT_EQ(context.dummyPtr, array.begin());
-            EXPECT_EQ(context.dummyPtr + LARGE_ARRAY_SIZE, array.end());
-            EXPECT_EQ(LARGE_ARRAY_SIZE, array.size());
-        }
-        EXPECT_EQ(context.getArrayElementsCallCount, context.releaseArrayElementsCallCount);
-        EXPECT_FALSE(context.memoryUpdated());
-        EXPECT_FALSE(context.aborted);
-    }
-    {
-        context.resetCallCount();
-        {
-            ScopedArrayRO<TestType, false /* non null */> array(env, nullptr);
-            EXPECT_TRUE(context.aborted);
-        }
-    }
-}
-
-TEST(ScopedPrimitiveArrayTest, testNullableArray) {
-    std::unique_ptr<TestType[]> dummyTestType = std::make_unique<TestType[]>(LARGE_ARRAY_SIZE);
-
-    TestContext context;
-    context.dummyPtr = dummyTestType.get();
-
-    JNIEnv* env = reinterpret_cast<JNIEnv*>(&context);
-    {
-        context.resetCallCount();
-        {
-            ScopedArrayRO<TestType, true /* nullable */> array(env, SMALL_ARRAY);
-            EXPECT_NE(nullptr, array.get());
-            EXPECT_EQ(SMALL_ARRAY, array.getJavaArray());
-            EXPECT_NE(nullptr, array.begin());
-            EXPECT_NE(nullptr, array.end());
-            EXPECT_EQ(array.end(), array.begin() + SMALL_ARRAY_SIZE);
-            EXPECT_EQ(SMALL_ARRAY_SIZE, (size_t) array.size());
-        }
-        EXPECT_EQ(context.getArrayElementsCallCount, context.releaseArrayElementsCallCount);
-        EXPECT_FALSE(context.memoryUpdated());
-        EXPECT_FALSE(context.aborted);
-    }
-    {
-        context.resetCallCount();
-        {
-            ScopedArrayRO<TestType, true /* nullable */> array(env, LARGE_ARRAY);
-            EXPECT_EQ(context.dummyPtr, array.get());
-            EXPECT_EQ(LARGE_ARRAY, array.getJavaArray());
-            EXPECT_EQ(context.dummyPtr, array.begin());
-            EXPECT_EQ(context.dummyPtr + LARGE_ARRAY_SIZE, array.end());
-            EXPECT_EQ(LARGE_ARRAY_SIZE, (size_t) array.size());
-        }
-        EXPECT_EQ(context.getArrayElementsCallCount, context.releaseArrayElementsCallCount);
-        EXPECT_FALSE(context.memoryUpdated());
-        EXPECT_FALSE(context.aborted);
-    }
-    {
-        context.resetCallCount();
-        {
-            ScopedArrayRO<TestType, true /* nullable*/> array(env, nullptr);
-            EXPECT_EQ(nullptr, array.get());
-            EXPECT_EQ(nullptr, array.getJavaArray());
-            EXPECT_EQ(nullptr, array.begin());
-            EXPECT_EQ(nullptr, array.end());
-            EXPECT_EQ(-1, array.size());
-        }
-        EXPECT_EQ(context.getArrayElementsCallCount, context.releaseArrayElementsCallCount);
-        EXPECT_FALSE(context.memoryUpdated());
-        EXPECT_FALSE(context.aborted);
-    }
-}
-
-TEST(ScopedPrimitiveArrayTest, testArrayRW) {
-    std::unique_ptr<TestType[]> dummyTestType = std::make_unique<TestType[]>(LARGE_ARRAY_SIZE);
-
-    TestContext context;
-    context.dummyPtr = dummyTestType.get();
-
-    JNIEnv* env = reinterpret_cast<JNIEnv*>(&context);
-    {
-        context.resetCallCount();
-        {
-            ScopedArrayRW<TestType> array(env, SMALL_ARRAY);
-            EXPECT_NE(nullptr, array.get());
-            EXPECT_EQ(SMALL_ARRAY, array.getJavaArray());
-            EXPECT_NE(nullptr, array.begin());
-            EXPECT_NE(nullptr, array.end());
-            EXPECT_EQ(array.end(), array.begin() + SMALL_ARRAY_SIZE);
-            EXPECT_EQ(SMALL_ARRAY_SIZE, (size_t) array.size());
-        }
-        EXPECT_EQ(context.getArrayElementsCallCount, context.releaseArrayElementsCallCount);
-        EXPECT_TRUE(context.memoryUpdated());
-        EXPECT_FALSE(context.aborted);
-    }
-    {
-        context.resetCallCount();
-        {
-            ScopedArrayRW<TestType> array(env, LARGE_ARRAY);
-            EXPECT_EQ(context.dummyPtr, array.get());
-            EXPECT_EQ(LARGE_ARRAY, array.getJavaArray());
-            EXPECT_EQ(context.dummyPtr, array.begin());
-            EXPECT_EQ(context.dummyPtr + LARGE_ARRAY_SIZE, array.end());
-            EXPECT_EQ(LARGE_ARRAY_SIZE, (size_t) array.size());
-        }
-        EXPECT_EQ(context.getArrayElementsCallCount, context.releaseArrayElementsCallCount);
-        EXPECT_TRUE(context.memoryUpdated());
-        EXPECT_FALSE(context.aborted);
-    }
-    {
-        context.resetCallCount();
-        {
-            ScopedArrayRW<TestType> array(env, nullptr);
-            EXPECT_TRUE(context.aborted);
-        }
-    }
-}