Nativehelper: Export header-only version of helpers

Export a version of the nativehelper helpers that doesn't have
a dependency on the libnativehelper library. Instead, provide an
inline function for null throw.

Test: m
Change-Id: Idfab8809873d54db824c8bc089f003265fe5a9b9
diff --git a/header_only_include/nativehelper/nativehelper_utils.h b/header_only_include/nativehelper/nativehelper_utils.h
new file mode 100644
index 0000000..da0c647
--- /dev/null
+++ b/header_only_include/nativehelper/nativehelper_utils.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef NATIVEHELPER_MACROS_H_
+#define NATIVEHELPER_MACROS_H_
+
+#if defined(__cplusplus)
+
+#if !defined(DISALLOW_COPY_AND_ASSIGN)
+// DISALLOW_COPY_AND_ASSIGN disallows the copy and operator= functions. It goes in the private:
+// declarations in a class.
+#if __cplusplus >= 201103L
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+  TypeName(const TypeName&) = delete;  \
+  void operator=(const TypeName&) = delete
+#else
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+  TypeName(const TypeName&);  \
+  void operator=(const TypeName&)
+#endif  // __has_feature(cxx_deleted_functions)
+#endif  // !defined(DISALLOW_COPY_AND_ASSIGN)
+
+#ifndef NATIVEHELPER_JNIHELP_H_
+// This seems a header-only include. Provide NPE throwing.
+static inline int jniThrowNullPointerException(JNIEnv* env, const char* msg) {
+    if (env->ExceptionCheck()) {
+        // Drop any pending exception.
+        env->ExceptionClear();
+    }
+
+    jclass e_class = env->FindClass("java/lang/NullPointerException");
+    if (e_class == nullptr) {
+        return -1;
+    }
+
+    if (env->ThrowNew(e_class, msg) != JNI_OK) {
+        env->DeleteLocalRef(e_class);
+        return -1;
+    }
+
+    env->DeleteLocalRef(e_class);
+    return 0;
+}
+#endif  // NATIVEHELPER_JNIHELP_H_
+
+#endif  // defined(__cplusplus)
+
+#endif  // NATIVEHELPER_MACROS_H_
diff --git a/header_only_include/nativehelper/scoped_bytes.h b/header_only_include/nativehelper/scoped_bytes.h
new file mode 100644
index 0000000..abeb395
--- /dev/null
+++ b/header_only_include/nativehelper/scoped_bytes.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef SCOPED_BYTES_H_
+#define SCOPED_BYTES_H_
+
+#include "jni.h"
+#include "nativehelper_utils.h"
+
+/**
+ * ScopedBytesRO and ScopedBytesRW attempt to paper over the differences between byte[]s and
+ * ByteBuffers. This in turn helps paper over the differences between non-direct ByteBuffers backed
+ * by byte[]s, direct ByteBuffers backed by bytes[]s, and direct ByteBuffers not backed by byte[]s.
+ * (On Android, this last group only contains MappedByteBuffers.)
+ */
+template<bool readOnly>
+class ScopedBytes {
+public:
+    ScopedBytes(JNIEnv* env, jobject object)
+    : mEnv(env), mObject(object), mByteArray(NULL), mPtr(NULL)
+    {
+        if (mObject == NULL) {
+            jniThrowNullPointerException(mEnv, NULL);
+        } else if (mEnv->IsInstanceOf(mObject, JniConstants::byteArrayClass)) {
+            mByteArray = reinterpret_cast<jbyteArray>(mObject);
+            mPtr = mEnv->GetByteArrayElements(mByteArray, NULL);
+        } else {
+            mPtr = reinterpret_cast<jbyte*>(mEnv->GetDirectBufferAddress(mObject));
+        }
+    }
+
+    ~ScopedBytes() {
+        if (mByteArray != NULL) {
+            mEnv->ReleaseByteArrayElements(mByteArray, mPtr, readOnly ? JNI_ABORT : 0);
+        }
+    }
+
+private:
+    JNIEnv* const mEnv;
+    const jobject mObject;
+    jbyteArray mByteArray;
+
+protected:
+    jbyte* mPtr;
+
+private:
+    DISALLOW_COPY_AND_ASSIGN(ScopedBytes);
+};
+
+class ScopedBytesRO : public ScopedBytes<true> {
+public:
+    ScopedBytesRO(JNIEnv* env, jobject object) : ScopedBytes<true>(env, object) {}
+    const jbyte* get() const {
+        return mPtr;
+    }
+};
+
+class ScopedBytesRW : public ScopedBytes<false> {
+public:
+    ScopedBytesRW(JNIEnv* env, jobject object) : ScopedBytes<false>(env, object) {}
+    jbyte* get() {
+        return mPtr;
+    }
+};
+
+#endif  // SCOPED_BYTES_H_
diff --git a/header_only_include/nativehelper/scoped_local_frame.h b/header_only_include/nativehelper/scoped_local_frame.h
new file mode 100644
index 0000000..70797f4
--- /dev/null
+++ b/header_only_include/nativehelper/scoped_local_frame.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef SCOPED_LOCAL_FRAME_H_
+#define SCOPED_LOCAL_FRAME_H_
+
+#include "jni.h"
+
+class ScopedLocalFrame {
+public:
+    explicit ScopedLocalFrame(JNIEnv* env) : mEnv(env) {
+        mEnv->PushLocalFrame(128);
+    }
+
+    ~ScopedLocalFrame() {
+        mEnv->PopLocalFrame(NULL);
+    }
+
+private:
+    JNIEnv* const mEnv;
+
+    DISALLOW_COPY_AND_ASSIGN(ScopedLocalFrame);
+};
+
+#endif  // SCOPED_LOCAL_FRAME_H_
diff --git a/header_only_include/nativehelper/scoped_local_ref.h b/header_only_include/nativehelper/scoped_local_ref.h
new file mode 100644
index 0000000..458c87f
--- /dev/null
+++ b/header_only_include/nativehelper/scoped_local_ref.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef SCOPED_LOCAL_REF_H_
+#define SCOPED_LOCAL_REF_H_
+
+#include <cstddef>
+
+#include "jni.h"
+#include "nativehelper_utils.h"
+
+// A smart pointer that deletes a JNI local reference when it goes out of scope.
+template<typename T>
+class ScopedLocalRef {
+public:
+    ScopedLocalRef(JNIEnv* env, T localRef) : mEnv(env), mLocalRef(localRef) {
+    }
+
+    ~ScopedLocalRef() {
+        reset();
+    }
+
+    void reset(T ptr = NULL) {
+        if (ptr != mLocalRef) {
+            if (mLocalRef != NULL) {
+                mEnv->DeleteLocalRef(mLocalRef);
+            }
+            mLocalRef = ptr;
+        }
+    }
+
+    T release() __attribute__((warn_unused_result)) {
+        T localRef = mLocalRef;
+        mLocalRef = NULL;
+        return localRef;
+    }
+
+    T get() const {
+        return mLocalRef;
+    }
+
+// Some better C++11 support.
+#if __cplusplus >= 201103L
+    // Move constructor.
+    ScopedLocalRef(ScopedLocalRef&& s) : mEnv(s.mEnv), mLocalRef(s.release()) {
+    }
+
+    explicit ScopedLocalRef(JNIEnv* env) : mEnv(env), mLocalRef(nullptr) {
+    }
+
+    // We do not expose an empty constructor as it can easily lead to errors
+    // using common idioms, e.g.:
+    //   ScopedLocalRef<...> ref;
+    //   ref.reset(...);
+
+    // Move assignment operator.
+    ScopedLocalRef& operator=(ScopedLocalRef&& s) {
+        reset(s.release());
+        mEnv = s.mEnv;
+        return *this;
+    }
+
+    // Allows "if (scoped_ref == nullptr)"
+    bool operator==(std::nullptr_t) const {
+        return mLocalRef == nullptr;
+    }
+
+    // Allows "if (scoped_ref != nullptr)"
+    bool operator!=(std::nullptr_t) const {
+        return mLocalRef != nullptr;
+    }
+#endif
+
+private:
+    JNIEnv* mEnv;
+    T mLocalRef;
+
+    DISALLOW_COPY_AND_ASSIGN(ScopedLocalRef);
+};
+
+#endif  // SCOPED_LOCAL_REF_H_
diff --git a/header_only_include/nativehelper/scoped_primitive_array.h b/header_only_include/nativehelper/scoped_primitive_array.h
new file mode 100644
index 0000000..d6840c2
--- /dev/null
+++ b/header_only_include/nativehelper/scoped_primitive_array.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef SCOPED_PRIMITIVE_ARRAY_H_
+#define SCOPED_PRIMITIVE_ARRAY_H_
+
+#include "jni.h"
+#include "nativehelper_utils.h"
+
+#ifdef POINTER_TYPE
+#error POINTER_TYPE is defined.
+#else
+#define POINTER_TYPE(T) T*  /* NOLINT */
+#endif
+
+#ifdef REFERENCE_TYPE
+#error REFERENCE_TYPE is defined.
+#else
+#define REFERENCE_TYPE(T) T&  /* NOLINT */
+#endif
+
+// 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); \
+    }
+
+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 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
+#undef REFERENCE_TYPE
+
+#endif  // SCOPED_PRIMITIVE_ARRAY_H_
diff --git a/header_only_include/nativehelper/scoped_string_chars.h b/header_only_include/nativehelper/scoped_string_chars.h
new file mode 100644
index 0000000..4debb2a
--- /dev/null
+++ b/header_only_include/nativehelper/scoped_string_chars.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#ifndef SCOPED_STRING_CHARS_H_
+#define SCOPED_STRING_CHARS_H_
+
+#include "jni.h"
+#include "nativehelper_utils.h"
+
+// A smart pointer that provides access to a jchar* given a JNI jstring.
+// Unlike GetStringChars, we throw NullPointerException rather than abort if
+// passed a null jstring, and get will return NULL.
+// This makes the correct idiom very simple:
+//
+//   ScopedStringChars name(env, java_name);
+//   if (name.get() == NULL) {
+//     return NULL;
+//   }
+class ScopedStringChars {
+ public:
+  ScopedStringChars(JNIEnv* env, jstring s) : env_(env), string_(s), size_(0) {
+    if (s == NULL) {
+      chars_ = NULL;
+      jniThrowNullPointerException(env, NULL);
+    } else {
+      chars_ = env->GetStringChars(string_, NULL);
+      if (chars_ != NULL) {
+        size_ = env->GetStringLength(string_);
+      }
+    }
+  }
+
+  ~ScopedStringChars() {
+    if (chars_ != NULL) {
+      env_->ReleaseStringChars(string_, chars_);
+    }
+  }
+
+  const jchar* get() const {
+    return chars_;
+  }
+
+  size_t size() const {
+    return size_;
+  }
+
+  const jchar& operator[](size_t n) const {
+    return chars_[n];
+  }
+
+ private:
+  JNIEnv* const env_;
+  const jstring string_;
+  const jchar* chars_;
+  size_t size_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedStringChars);
+};
+
+#endif  // SCOPED_STRING_CHARS_H_
diff --git a/header_only_include/nativehelper/scoped_utf_chars.h b/header_only_include/nativehelper/scoped_utf_chars.h
new file mode 100644
index 0000000..75cbe50
--- /dev/null
+++ b/header_only_include/nativehelper/scoped_utf_chars.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef SCOPED_UTF_CHARS_H_
+#define SCOPED_UTF_CHARS_H_
+
+#include <string.h>
+
+#include "jni.h"
+#include "nativehelper_utils.h"
+
+// A smart pointer that provides read-only access to a Java string's UTF chars.
+// Unlike GetStringUTFChars, we throw NullPointerException rather than abort if
+// passed a null jstring, and c_str will return nullptr.
+// This makes the correct idiom very simple:
+//
+//   ScopedUtfChars name(env, java_name);
+//   if (name.c_str() == nullptr) {
+//     return nullptr;
+//   }
+class ScopedUtfChars {
+ public:
+  ScopedUtfChars(JNIEnv* env, jstring s) : env_(env), string_(s) {
+    if (s == nullptr) {
+      utf_chars_ = nullptr;
+      jniThrowNullPointerException(env, nullptr);
+    } else {
+      utf_chars_ = env->GetStringUTFChars(s, nullptr);
+    }
+  }
+
+  ScopedUtfChars(ScopedUtfChars&& rhs) :
+      env_(rhs.env_), string_(rhs.string_), utf_chars_(rhs.utf_chars_) {
+    rhs.env_ = nullptr;
+    rhs.string_ = nullptr;
+    rhs.utf_chars_ = nullptr;
+  }
+
+  ~ScopedUtfChars() {
+    if (utf_chars_) {
+      env_->ReleaseStringUTFChars(string_, utf_chars_);
+    }
+  }
+
+  ScopedUtfChars& operator=(ScopedUtfChars&& rhs) {
+    if (this != &rhs) {
+      // Delete the currently owned UTF chars.
+      this->~ScopedUtfChars();
+
+      // Move the rhs ScopedUtfChars and zero it out.
+      env_ = rhs.env_;
+      string_ = rhs.string_;
+      utf_chars_ = rhs.utf_chars_;
+      rhs.env_ = nullptr;
+      rhs.string_ = nullptr;
+      rhs.utf_chars_ = nullptr;
+    }
+    return *this;
+  }
+
+  const char* c_str() const {
+    return utf_chars_;
+  }
+
+  size_t size() const {
+    return strlen(utf_chars_);
+  }
+
+  const char& operator[](size_t n) const {
+    return utf_chars_[n];
+  }
+
+ private:
+  JNIEnv* env_;
+  jstring string_;
+  const char* utf_chars_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedUtfChars);
+};
+
+#endif  // SCOPED_UTF_CHARS_H_