xref: /aosp_15_r20/external/icing/icing/text_classifier/lib3/utils/java/jni-base.h (revision 8b6cd535a057e39b3b86660c4aa06c99747c2136)
1 // Copyright (C) 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef ICING_TEXT_CLASSIFIER_LIB3_UTILS_JAVA_JNI_BASE_H_
16 #define ICING_TEXT_CLASSIFIER_LIB3_UTILS_JAVA_JNI_BASE_H_
17 
18 #include <jni.h>
19 
20 #include <memory>
21 #include <string>
22 
23 #include "icing/text_classifier/lib3/utils/base/statusor.h"
24 
25 // When we use a macro as an argument for a macro, an additional level of
26 // indirection is needed, if the macro argument is used with # or ##.
27 #define TC3_ADD_QUOTES_HELPER(TOKEN) #TOKEN
28 #define TC3_ADD_QUOTES(TOKEN) TC3_ADD_QUOTES_HELPER(TOKEN)
29 
30 #ifndef TC3_PACKAGE_NAME
31 #define TC3_PACKAGE_NAME com_google_knowledge_cerebra_sense_textclassifier_lib3
32 #endif
33 
34 #ifndef TC3_PACKAGE_PATH
35 #define TC3_PACKAGE_PATH \
36   "com/google/knowledge/cerebra/sense/textclassifier/lib3/"
37 #endif
38 
39 #define TC3_JNI_METHOD_NAME_INTERNAL(package_name, class_name, method_name) \
40   Java_##package_name##_##class_name##_##method_name
41 
42 #define TC3_JNI_METHOD_PRIMITIVE(return_type, package_name, class_name, \
43                                  method_name)                           \
44   JNIEXPORT return_type JNICALL TC3_JNI_METHOD_NAME_INTERNAL(           \
45       package_name, class_name, method_name)
46 
47 // The indirection is needed to correctly expand the TC3_PACKAGE_NAME macro.
48 // See the explanation near TC3_ADD_QUOTES macro.
49 #define TC3_JNI_METHOD2(return_type, package_name, class_name, method_name) \
50   TC3_JNI_METHOD_PRIMITIVE(return_type, package_name, class_name, method_name)
51 
52 #define TC3_JNI_METHOD(return_type, class_name, method_name) \
53   TC3_JNI_METHOD2(return_type, TC3_PACKAGE_NAME, class_name, method_name)
54 
55 #define TC3_JNI_METHOD_NAME2(package_name, class_name, method_name) \
56   TC3_JNI_METHOD_NAME_INTERNAL(package_name, class_name, method_name)
57 
58 #define TC3_JNI_METHOD_NAME(class_name, method_name) \
59   TC3_JNI_METHOD_NAME2(TC3_PACKAGE_NAME, class_name, method_name)
60 
61 namespace libtextclassifier3 {
62 
63 // Returns true if the requested capacity is available.
64 bool EnsureLocalCapacity(JNIEnv* env, int capacity);
65 
66 // Returns true if there was an exception. Also it clears the exception.
67 bool JniExceptionCheckAndClear(JNIEnv* env,
68                                bool print_exception_on_error = true);
69 
70 // A deleter to be used with std::unique_ptr to delete JNI global references.
71 class GlobalRefDeleter {
72  public:
GlobalRefDeleter(JavaVM * jvm)73   explicit GlobalRefDeleter(JavaVM* jvm) : jvm_(jvm) {}
74 
75   GlobalRefDeleter(const GlobalRefDeleter& orig) = default;
76 
77   // Copy assignment to allow move semantics in ScopedGlobalRef.
78   GlobalRefDeleter& operator=(const GlobalRefDeleter& rhs) {
79     TC3_CHECK_EQ(jvm_, rhs.jvm_);
80     return *this;
81   }
82 
83   // The delete operator.
operator()84   void operator()(jobject object) const {
85     JNIEnv* env;
86     if (object != nullptr && jvm_ != nullptr &&
87         JNI_OK ==
88             jvm_->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_4)) {
89       env->DeleteGlobalRef(object);
90     }
91   }
92 
93  private:
94   // The jvm_ stashed to use for deletion.
95   JavaVM* const jvm_;
96 };
97 
98 // A deleter to be used with std::unique_ptr to delete JNI local references.
99 class LocalRefDeleter {
100  public:
LocalRefDeleter(JNIEnv * env)101   explicit LocalRefDeleter(JNIEnv* env)
102       : env_(env) {}  // NOLINT(runtime/explicit)
103 
104   LocalRefDeleter(const LocalRefDeleter& orig) = default;
105 
106   // Copy assignment to allow move semantics in ScopedLocalRef.
107   LocalRefDeleter& operator=(const LocalRefDeleter& rhs) {
108     env_ = rhs.env_;
109     return *this;
110   }
111 
112   // The delete operator.
operator()113   void operator()(jobject object) const {
114     if (env_) {
115       env_->DeleteLocalRef(object);
116     }
117   }
118 
119  private:
120   // The env_ stashed to use for deletion. Thread-local, don't share!
121   JNIEnv* env_;
122 };
123 
124 // A smart pointer that deletes a reference when it goes out of scope.
125 //
126 // Note that this class is not thread-safe since it caches JNIEnv in
127 // the deleter. Do not use the same jobject across different threads.
128 template <typename T, typename Env, typename Deleter>
129 class ScopedRef {
130  public:
ScopedRef()131   ScopedRef() : ptr_(nullptr, Deleter(nullptr)) {}
ScopedRef(T value,Env * env)132   ScopedRef(T value, Env* env) : ptr_(value, Deleter(env)) {}
133 
get()134   T get() const { return ptr_.get(); }
135 
release()136   T release() { return ptr_.release(); }
137 
138   bool operator!() const { return !ptr_; }
139 
140   bool operator==(void* value) const { return ptr_.get() == value; }
141 
142   explicit operator bool() const { return ptr_ != nullptr; }
143 
reset(T value,Env * env)144   void reset(T value, Env* env) {
145     ptr_.reset(value);
146     ptr_.get_deleter() = Deleter(env);
147   }
148 
149  private:
150   std::unique_ptr<typename std::remove_pointer<T>::type, Deleter> ptr_;
151 };
152 
153 template <typename T, typename U, typename Env, typename Deleter>
154 inline bool operator==(const ScopedRef<T, Env, Deleter>& x,
155                        const ScopedRef<U, Env, Deleter>& y) {
156   return x.get() == y.get();
157 }
158 
159 template <typename T, typename Env, typename Deleter>
160 inline bool operator==(const ScopedRef<T, Env, Deleter>& x, std::nullptr_t) {
161   return x.get() == nullptr;
162 }
163 
164 template <typename T, typename Env, typename Deleter>
165 inline bool operator==(std::nullptr_t, const ScopedRef<T, Env, Deleter>& x) {
166   return nullptr == x.get();
167 }
168 
169 template <typename T, typename U, typename Env, typename Deleter>
170 inline bool operator!=(const ScopedRef<T, Env, Deleter>& x,
171                        const ScopedRef<U, Env, Deleter>& y) {
172   return x.get() != y.get();
173 }
174 
175 template <typename T, typename Env, typename Deleter>
176 inline bool operator!=(const ScopedRef<T, Env, Deleter>& x, std::nullptr_t) {
177   return x.get() != nullptr;
178 }
179 
180 template <typename T, typename Env, typename Deleter>
181 inline bool operator!=(std::nullptr_t, const ScopedRef<T, Env, Deleter>& x) {
182   return nullptr != x.get();
183 }
184 
185 template <typename T, typename U, typename Env, typename Deleter>
186 inline bool operator<(const ScopedRef<T, Env, Deleter>& x,
187                       const ScopedRef<U, Env, Deleter>& y) {
188   return x.get() < y.get();
189 }
190 
191 template <typename T, typename U, typename Env, typename Deleter>
192 inline bool operator>(const ScopedRef<T, Env, Deleter>& x,
193                       const ScopedRef<U, Env, Deleter>& y) {
194   return x.get() > y.get();
195 }
196 
197 // A smart pointer that deletes a JNI global reference when it goes out
198 // of scope. Usage is:
199 // ScopedGlobalRef<jobject> scoped_global(env->JniFunction(), jvm);
200 template <typename T>
201 using ScopedGlobalRef = ScopedRef<T, JavaVM, GlobalRefDeleter>;
202 
203 // Ditto, but usage is:
204 // ScopedLocalRef<jobject> scoped_local(env->JniFunction(), env);
205 template <typename T>
206 using ScopedLocalRef = ScopedRef<T, JNIEnv, LocalRefDeleter>;
207 
208 // A helper to create global references.
209 template <typename T>
MakeGlobalRef(T object,JNIEnv * env,JavaVM * jvm)210 ScopedGlobalRef<T> MakeGlobalRef(T object, JNIEnv* env, JavaVM* jvm) {
211   const jobject global_object = env->NewGlobalRef(object);
212   return ScopedGlobalRef<T>(reinterpret_cast<T>(global_object), jvm);
213 }
214 
215 }  // namespace libtextclassifier3
216 
217 #endif  // ICING_TEXT_CLASSIFIER_LIB3_UTILS_JAVA_JNI_BASE_H_
218