WPILibC++  unspecified
jni_util.h
1 /*----------------------------------------------------------------------------*/
2 /* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
3 /* Open Source Software - may be modified and shared by FRC teams. The code */
4 /* must be accompanied by the FIRST BSD license file in the root directory of */
5 /* the project. */
6 /*----------------------------------------------------------------------------*/
7 
8 #ifndef WPIUTIL_WPI_JNI_UTIL_H_
9 #define WPIUTIL_WPI_JNI_UTIL_H_
10 
11 #include <jni.h>
12 
13 #include <queue>
14 #include <string>
15 #include <type_traits>
16 #include <utility>
17 #include <vector>
18 
19 #include "wpi/ArrayRef.h"
20 #include "wpi/ConvertUTF.h"
21 #include "wpi/SafeThread.h"
22 #include "wpi/SmallString.h"
23 #include "wpi/SmallVector.h"
24 #include "wpi/StringRef.h"
25 #include "wpi/deprecated.h"
26 #include "wpi/mutex.h"
27 #include "wpi/raw_ostream.h"
28 
29 namespace wpi {
30 namespace java {
31 
32 // Gets a Java stack trace. Also provides the last function
33 // in the stack trace not starting with excludeFuncPrefix (useful for e.g.
34 // finding the first user call to a series of library functions).
35 std::string GetJavaStackTrace(JNIEnv* env, std::string* func = nullptr,
36  StringRef excludeFuncPrefix = StringRef());
37 
38 // Shim for backwards compatibility
39 template <const char* excludeFuncPrefix>
40 WPI_DEPRECATED("use StringRef function instead")
41 std::string GetJavaStackTrace(JNIEnv* env, std::string* func) {
42  return GetJavaStackTrace(
43  env, func,
44  excludeFuncPrefix == nullptr ? StringRef() : excludeFuncPrefix);
45 }
46 
47 // Finds a class and keep it as a global reference.
48 // Use with caution, as the destructor does NOT call DeleteGlobalRef due
49 // to potential shutdown issues with doing so.
50 class JClass {
51  public:
52  JClass() = default;
53 
54  JClass(JNIEnv* env, const char* name) {
55  jclass local = env->FindClass(name);
56  if (!local) return;
57  m_cls = static_cast<jclass>(env->NewGlobalRef(local));
58  env->DeleteLocalRef(local);
59  }
60 
61  void free(JNIEnv* env) {
62  if (m_cls) env->DeleteGlobalRef(m_cls);
63  m_cls = nullptr;
64  }
65 
66  explicit operator bool() const { return m_cls; }
67 
68  operator jclass() const { return m_cls; }
69 
70  protected:
71  jclass m_cls = nullptr;
72 };
73 
74 struct JClassInit {
75  const char* name;
76  JClass* cls;
77 };
78 
79 template <typename T>
80 class JGlobal {
81  public:
82  JGlobal() = default;
83 
84  JGlobal(JNIEnv* env, T obj) {
85  m_cls = static_cast<T>(env->NewGlobalRef(obj));
86  }
87 
88  void free(JNIEnv* env) {
89  if (m_cls) env->DeleteGlobalRef(m_cls);
90  m_cls = nullptr;
91  }
92 
93  explicit operator bool() const { return m_cls; }
94 
95  operator T() const { return m_cls; }
96 
97  protected:
98  T m_cls = nullptr;
99 };
100 
101 // Container class for cleaning up Java local references.
102 // The destructor calls DeleteLocalRef.
103 template <typename T>
104 class JLocal {
105  public:
106  JLocal(JNIEnv* env, T obj) : m_env(env), m_obj(obj) {}
107  JLocal(const JLocal&) = delete;
108  JLocal(JLocal&& oth) : m_env(oth.m_env), m_obj(oth.m_obj) {
109  oth.m_obj = nullptr;
110  }
111  JLocal& operator=(const JLocal&) = delete;
112  JLocal& operator=(JLocal&& oth) {
113  m_env = oth.m_env;
114  m_obj = oth.m_obj;
115  oth.m_obj = nullptr;
116  return *this;
117  }
118  ~JLocal() {
119  if (m_obj) m_env->DeleteLocalRef(m_obj);
120  }
121  operator T() { return m_obj; }
122  T obj() { return m_obj; }
123 
124  private:
125  JNIEnv* m_env;
126  T m_obj;
127 };
128 
129 //
130 // Conversions from Java objects to C++
131 //
132 
133 // Java string (jstring) reference. The string is provided as UTF8.
134 // This is not actually a reference, as it makes a copy of the string
135 // characters, but it's named this way for consistency.
136 class JStringRef {
137  public:
138  JStringRef(JNIEnv* env, jstring str) {
139  if (str) {
140  jsize size = env->GetStringLength(str);
141  const jchar* chars = env->GetStringCritical(str, nullptr);
142  if (chars) {
143  convertUTF16ToUTF8String(makeArrayRef(chars, size), m_str);
144  env->ReleaseStringCritical(str, chars);
145  }
146  } else {
147  errs() << "JStringRef was passed a null pointer at \n"
148  << GetJavaStackTrace(env);
149  }
150  // Ensure str is null-terminated.
151  m_str.push_back('\0');
152  m_str.pop_back();
153  }
154 
155  operator StringRef() const { return m_str; }
156  StringRef str() const { return m_str; }
157  const char* c_str() const { return m_str.data(); }
158  size_t size() const { return m_str.size(); }
159 
160  private:
161  SmallString<128> m_str;
162 };
163 
164 // Details for J*ArrayRef and CriticalJ*ArrayRef
165 namespace detail {
166 
167 template <typename C, typename T>
168 class JArrayRefInner {};
169 
170 // Specialization of JArrayRefBase to provide StringRef conversion.
171 template <typename C>
172 class JArrayRefInner<C, jbyte> {
173  public:
174  operator StringRef() const { return str(); }
175 
176  StringRef str() const {
177  auto arr = static_cast<const C*>(this)->array();
178  if (arr.empty()) return StringRef{};
179  return StringRef{reinterpret_cast<const char*>(arr.data()), arr.size()};
180  }
181 };
182 
183 // Base class for J*ArrayRef and CriticalJ*ArrayRef
184 template <typename T>
185 class JArrayRefBase : public JArrayRefInner<JArrayRefBase<T>, T> {
186  public:
187  explicit operator bool() const { return this->m_elements != nullptr; }
188 
189  operator ArrayRef<T>() const { return array(); }
190 
191  ArrayRef<T> array() const {
192  if (!this->m_elements) return ArrayRef<T>{};
193  return ArrayRef<T>{this->m_elements, this->m_size};
194  }
195 
196  JArrayRefBase(const JArrayRefBase&) = delete;
197  JArrayRefBase& operator=(const JArrayRefBase&) = delete;
198 
200  : m_env(oth.m_env),
201  m_jarr(oth.m_jarr),
202  m_size(oth.m_size),
203  m_elements(oth.m_elements) {
204  oth.m_jarr = nullptr;
205  oth.m_elements = nullptr;
206  }
207 
208  JArrayRefBase& operator=(JArrayRefBase&& oth) {
209  this->m_env = oth.m_env;
210  this->m_jarr = oth.m_jarr;
211  this->m_size = oth.m_size;
212  this->m_elements = oth.m_elements;
213  oth.m_jarr = nullptr;
214  oth.m_elements = nullptr;
215  return *this;
216  }
217 
218  protected:
219  JArrayRefBase(JNIEnv* env, T* elements, size_t size) {
220  this->m_env = env;
221  this->m_jarr = nullptr;
222  this->m_size = size;
223  this->m_elements = elements;
224  }
225 
226  JArrayRefBase(JNIEnv* env, jarray jarr) {
227  this->m_env = env;
228  this->m_jarr = jarr;
229  this->m_size = jarr ? env->GetArrayLength(jarr) : 0;
230  this->m_elements = nullptr;
231  }
232 
233  JNIEnv* m_env;
234  jarray m_jarr = nullptr;
235  size_t m_size;
236  T* m_elements;
237 };
238 
239 } // namespace detail
240 
241 // Java array / DirectBuffer reference.
242 
243 #define WPI_JNI_JARRAYREF(T, F) \
244  class J##F##ArrayRef : public detail::JArrayRefBase<T> { \
245  public: \
246  J##F##ArrayRef(JNIEnv* env, jobject bb, int len) \
247  : detail::JArrayRefBase<T>( \
248  env, \
249  static_cast<T*>(bb ? env->GetDirectBufferAddress(bb) : nullptr), \
250  len) { \
251  if (!bb) \
252  errs() << "JArrayRef was passed a null pointer at \n" \
253  << GetJavaStackTrace(env); \
254  } \
255  J##F##ArrayRef(JNIEnv* env, T##Array jarr) \
256  : detail::JArrayRefBase<T>(env, jarr) { \
257  if (jarr) \
258  m_elements = env->Get##F##ArrayElements(jarr, nullptr); \
259  else \
260  errs() << "JArrayRef was passed a null pointer at \n" \
261  << GetJavaStackTrace(env); \
262  } \
263  ~J##F##ArrayRef() { \
264  if (m_jarr && m_elements) \
265  m_env->Release##F##ArrayElements(static_cast<T##Array>(m_jarr), \
266  m_elements, JNI_ABORT); \
267  } \
268  }; \
269  \
270  class CriticalJ##F##ArrayRef : public detail::JArrayRefBase<T> { \
271  public: \
272  CriticalJ##F##ArrayRef(JNIEnv* env, T##Array jarr) \
273  : detail::JArrayRefBase<T>(env, jarr) { \
274  if (jarr) \
275  m_elements = \
276  static_cast<T*>(env->GetPrimitiveArrayCritical(jarr, nullptr)); \
277  else \
278  errs() << "JArrayRef was passed a null pointer at \n" \
279  << GetJavaStackTrace(env); \
280  } \
281  ~CriticalJ##F##ArrayRef() { \
282  if (m_jarr && m_elements) \
283  m_env->ReleasePrimitiveArrayCritical(m_jarr, m_elements, JNI_ABORT); \
284  } \
285  };
286 
287 WPI_JNI_JARRAYREF(jboolean, Boolean)
288 WPI_JNI_JARRAYREF(jbyte, Byte)
289 WPI_JNI_JARRAYREF(jshort, Short)
290 WPI_JNI_JARRAYREF(jint, Int)
291 WPI_JNI_JARRAYREF(jlong, Long)
292 WPI_JNI_JARRAYREF(jfloat, Float)
293 WPI_JNI_JARRAYREF(jdouble, Double)
294 
295 #undef WPI_JNI_JARRAYREF
296 
297 //
298 // Conversions from C++ to Java objects
299 //
300 
301 // Convert a UTF8 string into a jstring.
302 inline jstring MakeJString(JNIEnv* env, StringRef str) {
304  convertUTF8ToUTF16String(str, chars);
305  return env->NewString(chars.begin(), chars.size());
306 }
307 
308 // details for MakeJIntArray
309 namespace detail {
310 
311 // Slow path (get primitive array and set individual elements). This
312 // is used if the input type is not an integer of the same size (note
313 // signed/unsigned is ignored).
314 template <typename T,
315  bool = (std::is_integral<T>::value && sizeof(jint) == sizeof(T))>
317  static jintArray ToJava(JNIEnv* env, ArrayRef<T> arr) {
318  jintArray jarr = env->NewIntArray(arr.size());
319  if (!jarr) return nullptr;
320  jint* elements =
321  static_cast<jint*>(env->GetPrimitiveArrayCritical(jarr, nullptr));
322  if (!elements) return nullptr;
323  for (size_t i = 0; i < arr.size(); ++i)
324  elements[i] = static_cast<jint>(arr[i]);
325  env->ReleasePrimitiveArrayCritical(jarr, elements, 0);
326  return jarr;
327  }
328 };
329 
330 // Fast path (use SetIntArrayRegion)
331 template <typename T>
333  static jintArray ToJava(JNIEnv* env, ArrayRef<T> arr) {
334  jintArray jarr = env->NewIntArray(arr.size());
335  if (!jarr) return nullptr;
336  env->SetIntArrayRegion(jarr, 0, arr.size(),
337  reinterpret_cast<const jint*>(arr.data()));
338  return jarr;
339  }
340 };
341 
342 } // namespace detail
343 
344 // Convert an ArrayRef to a jintArray.
345 template <typename T>
346 inline jintArray MakeJIntArray(JNIEnv* env, ArrayRef<T> arr) {
347  return detail::ConvertIntArray<T>::ToJava(env, arr);
348 }
349 
350 // Convert a SmallVector to a jintArray. This is required in addition to
351 // ArrayRef because template resolution occurs prior to implicit conversions.
352 template <typename T>
353 inline jintArray MakeJIntArray(JNIEnv* env, const SmallVectorImpl<T>& arr) {
354  return detail::ConvertIntArray<T>::ToJava(env, arr);
355 }
356 
357 // Convert a std::vector to a jintArray. This is required in addition to
358 // ArrayRef because template resolution occurs prior to implicit conversions.
359 template <typename T>
360 inline jintArray MakeJIntArray(JNIEnv* env, const std::vector<T>& arr) {
361  return detail::ConvertIntArray<T>::ToJava(env, arr);
362 }
363 
364 // Convert a StringRef into a jbyteArray.
365 inline jbyteArray MakeJByteArray(JNIEnv* env, StringRef str) {
366  jbyteArray jarr = env->NewByteArray(str.size());
367  if (!jarr) return nullptr;
368  env->SetByteArrayRegion(jarr, 0, str.size(),
369  reinterpret_cast<const jbyte*>(str.data()));
370  return jarr;
371 }
372 
373 // Convert an array of integers into a jbooleanArray.
374 inline jbooleanArray MakeJBooleanArray(JNIEnv* env, ArrayRef<int> arr) {
375  jbooleanArray jarr = env->NewBooleanArray(arr.size());
376  if (!jarr) return nullptr;
377  jboolean* elements =
378  static_cast<jboolean*>(env->GetPrimitiveArrayCritical(jarr, nullptr));
379  if (!elements) return nullptr;
380  for (size_t i = 0; i < arr.size(); ++i)
381  elements[i] = arr[i] ? JNI_TRUE : JNI_FALSE;
382  env->ReleasePrimitiveArrayCritical(jarr, elements, 0);
383  return jarr;
384 }
385 
386 // Convert an array of booleans into a jbooleanArray.
387 inline jbooleanArray MakeJBooleanArray(JNIEnv* env, ArrayRef<bool> arr) {
388  jbooleanArray jarr = env->NewBooleanArray(arr.size());
389  if (!jarr) return nullptr;
390  jboolean* elements =
391  static_cast<jboolean*>(env->GetPrimitiveArrayCritical(jarr, nullptr));
392  if (!elements) return nullptr;
393  for (size_t i = 0; i < arr.size(); ++i)
394  elements[i] = arr[i] ? JNI_TRUE : JNI_FALSE;
395  env->ReleasePrimitiveArrayCritical(jarr, elements, 0);
396  return jarr;
397 }
398 
399  // Other MakeJ*Array conversions.
400 
401 #define WPI_JNI_MAKEJARRAY(T, F) \
402  inline T##Array MakeJ##F##Array(JNIEnv* env, ArrayRef<T> arr) { \
403  T##Array jarr = env->New##F##Array(arr.size()); \
404  if (!jarr) return nullptr; \
405  env->Set##F##ArrayRegion(jarr, 0, arr.size(), arr.data()); \
406  return jarr; \
407  }
408 
409 WPI_JNI_MAKEJARRAY(jboolean, Boolean)
410 WPI_JNI_MAKEJARRAY(jbyte, Byte)
411 WPI_JNI_MAKEJARRAY(jshort, Short)
412 WPI_JNI_MAKEJARRAY(jlong, Long)
413 WPI_JNI_MAKEJARRAY(jfloat, Float)
414 WPI_JNI_MAKEJARRAY(jdouble, Double)
415 
416 #undef WPI_JNI_MAKEJARRAY
417 
418 // Convert an array of std::string into a jarray of jstring.
419 inline jobjectArray MakeJStringArray(JNIEnv* env, ArrayRef<std::string> arr) {
420  static JClass stringCls{env, "java/lang/String"};
421  if (!stringCls) return nullptr;
422  jobjectArray jarr = env->NewObjectArray(arr.size(), stringCls, nullptr);
423  if (!jarr) return nullptr;
424  for (size_t i = 0; i < arr.size(); ++i) {
425  JLocal<jstring> elem{env, MakeJString(env, arr[i])};
426  env->SetObjectArrayElement(jarr, i, elem.obj());
427  }
428  return jarr;
429 }
430 
431 // Generic callback thread implementation.
432 //
433 // JNI's AttachCurrentThread() creates a Java Thread object on every
434 // invocation, which is both time inefficient and causes issues with Eclipse
435 // (which tries to keep a thread list up-to-date and thus gets swamped).
436 //
437 // Instead, this class attaches just once. When a hardware notification
438 // occurs, a condition variable wakes up this thread and this thread actually
439 // makes the call into Java.
440 //
441 // The template parameter T is the message being passed to the callback, but
442 // also needs to provide the following functions:
443 // static JavaVM* GetJVM();
444 // static const char* GetName();
445 // void CallJava(JNIEnv *env, jobject func, jmethodID mid);
446 template <typename T>
447 class JCallbackThread : public SafeThread {
448  public:
449  void Main();
450 
451  std::queue<T> m_queue;
452  jobject m_func = nullptr;
453  jmethodID m_mid;
454 };
455 
456 template <typename T>
458  public:
459  void SetFunc(JNIEnv* env, jobject func, jmethodID mid);
460 
461  template <typename... Args>
462  void Send(Args&&... args);
463 };
464 
465 template <typename T>
466 void JCallbackManager<T>::SetFunc(JNIEnv* env, jobject func, jmethodID mid) {
467  auto thr = this->GetThread();
468  if (!thr) return;
469  // free global reference
470  if (thr->m_func) env->DeleteGlobalRef(thr->m_func);
471  // create global reference
472  thr->m_func = env->NewGlobalRef(func);
473  thr->m_mid = mid;
474 }
475 
476 template <typename T>
477 template <typename... Args>
478 void JCallbackManager<T>::Send(Args&&... args) {
479  auto thr = this->GetThread();
480  if (!thr) return;
481  thr->m_queue.emplace(std::forward<Args>(args)...);
482  thr->m_cond.notify_one();
483 }
484 
485 template <typename T>
487  JNIEnv* env;
488  JavaVMAttachArgs args;
489  args.version = JNI_VERSION_1_2;
490  args.name = const_cast<char*>(T::GetName());
491  args.group = nullptr;
492  jint rs = T::GetJVM()->AttachCurrentThreadAsDaemon(
493  reinterpret_cast<void**>(&env), &args);
494  if (rs != JNI_OK) return;
495 
496  std::unique_lock<wpi::mutex> lock(m_mutex);
497  while (m_active) {
498  m_cond.wait(lock, [&] { return !(m_active && m_queue.empty()); });
499  if (!m_active) break;
500  while (!m_queue.empty()) {
501  if (!m_active) break;
502  auto item = std::move(m_queue.front());
503  m_queue.pop();
504  auto func = m_func;
505  auto mid = m_mid;
506  lock.unlock(); // don't hold mutex during callback execution
507  item.CallJava(env, func, mid);
508  if (env->ExceptionCheck()) {
509  env->ExceptionDescribe();
510  env->ExceptionClear();
511  }
512  lock.lock();
513  }
514  }
515 
516  JavaVM* jvm = T::GetJVM();
517  if (jvm) jvm->DetachCurrentThread();
518 }
519 
520 template <typename T>
522  public:
523  static JSingletonCallbackManager<T>& GetInstance() {
524  static JSingletonCallbackManager<T> instance;
525  return instance;
526  }
527 };
528 
529 inline std::string GetJavaStackTrace(JNIEnv* env, std::string* func,
530  StringRef excludeFuncPrefix) {
531  // create a throwable
532  static JClass throwableCls(env, "java/lang/Throwable");
533  if (!throwableCls) return "";
534  static jmethodID constructorId = nullptr;
535  if (!constructorId)
536  constructorId = env->GetMethodID(throwableCls, "<init>", "()V");
537  JLocal<jobject> throwable(env, env->NewObject(throwableCls, constructorId));
538 
539  // retrieve information from the exception.
540  // get method id
541  // getStackTrace returns an array of StackTraceElement
542  static jmethodID getStackTraceId = nullptr;
543  if (!getStackTraceId)
544  getStackTraceId = env->GetMethodID(throwableCls, "getStackTrace",
545  "()[Ljava/lang/StackTraceElement;");
546 
547  // call getStackTrace
548  JLocal<jobjectArray> stackTrace(
549  env, static_cast<jobjectArray>(
550  env->CallObjectMethod(throwable, getStackTraceId)));
551 
552  if (!stackTrace) return "";
553 
554  // get length of the array
555  jsize stackTraceLength = env->GetArrayLength(stackTrace);
556 
557  // get toString methodId of StackTraceElement class
558  static JClass stackTraceElementCls(env, "java/lang/StackTraceElement");
559  if (!stackTraceElementCls) return "";
560  static jmethodID toStringId = nullptr;
561  if (!toStringId)
562  toStringId = env->GetMethodID(stackTraceElementCls, "toString",
563  "()Ljava/lang/String;");
564 
565  bool haveLoc = false;
566  std::string buf;
567  raw_string_ostream oss(buf);
568  for (jsize i = 0; i < stackTraceLength; i++) {
569  // add the result of toString method of each element in the result
570  JLocal<jobject> curStackTraceElement(
571  env, env->GetObjectArrayElement(stackTrace, i));
572 
573  // call to string on the object
574  JLocal<jstring> stackElementString(
575  env, static_cast<jstring>(
576  env->CallObjectMethod(curStackTraceElement, toStringId)));
577 
578  if (!stackElementString) return "";
579 
580  // add a line to res
581  JStringRef elem(env, stackElementString);
582  oss << elem << '\n';
583 
584  if (func) {
585  // func is caller of immediate caller (if there was one)
586  // or, if we see it, the first user function
587  if (i == 1) {
588  *func = elem.str();
589  } else if (i > 1 && !haveLoc && !excludeFuncPrefix.empty() &&
590  !elem.str().startswith(excludeFuncPrefix)) {
591  *func = elem.str();
592  haveLoc = true;
593  }
594  }
595  }
596 
597  return oss.str();
598 }
599 
600 // Finds an exception class and keep it as a global reference.
601 // Similar to JClass, but provides Throw methods.
602 // Use with caution, as the destructor does NOT call DeleteGlobalRef due
603 // to potential shutdown issues with doing so.
604 class JException : public JClass {
605  public:
606  JException() = default;
607  JException(JNIEnv* env, const char* name) : JClass(env, name) {
608  if (m_cls)
609  m_constructor =
610  env->GetMethodID(m_cls, "<init>", "(Ljava/lang/String;)V");
611  }
612 
613  void Throw(JNIEnv* env, jstring msg) {
614  jobject exception = env->NewObject(m_cls, m_constructor, msg);
615  env->Throw(static_cast<jthrowable>(exception));
616  }
617 
618  void Throw(JNIEnv* env, StringRef msg) { Throw(env, MakeJString(env, msg)); }
619 
620  explicit operator bool() const { return m_constructor; }
621 
622  private:
623  jmethodID m_constructor = nullptr;
624 };
625 
627  const char* name;
628  JException* cls;
629 };
630 
631 } // namespace java
632 } // namespace wpi
633 
634 #endif // WPIUTIL_WPI_JNI_UTIL_H_
Definition: SafeThread.h:20
This is a &#39;vector&#39; (really, a variable-sized array), optimized for the case when the array is small...
Definition: SmallVector.h:868
Definition: jni_util.h:185
Definition: jni_util.h:626
Definition: jni_util.h:168
Definition: jni_util.h:50
Definition: SmallVector.h:946
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory)...
Definition: ArrayRef.h:41
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE const char * data() const noexcept
data - Get a pointer to the start of the string (which may not be null terminated).
Definition: StringRef.h:128
Definition: SafeThread.h:120
namespace to hold default to_json function
Definition: json_binary_writer.cpp:39
Definition: jni_util.h:80
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:482
raw_ostream & errs()
This returns a reference to a raw_ostream for standard error.
Definition: raw_ostream.cpp:685
ArrayRef< T > makeArrayRef(const T &OneElt)
Construct an ArrayRef from a single element.
Definition: ArrayRef.h:451
Definition: jni_util.h:447
bool convertUTF8ToUTF16String(StringRef SrcUTF8, SmallVectorImpl< UTF16 > &DstUTF16)
Converts a UTF-8 string into a UTF-16 string with native endianness.
Definition: ConvertUTFWrapper.cpp:83
Definition: jni_util.h:316
Definition: jni_util.h:521
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE bool empty() const noexcept
empty - Check if the string is empty.
Definition: StringRef.h:133
bool convertUTF16ToUTF8String(ArrayRef< UTF16 > SrcUTF16, SmallVectorImpl< char > &DstUTF8)
Converts a UTF-16 string into a UTF-8 string.
Definition: ConvertUTFWrapper.cpp:37
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: WindowsSupport.h:184
auto size(R &&Range, typename std::enable_if< std::is_same< typename std::iterator_traits< decltype(Range.begin())>::iterator_category, std::random_access_iterator_tag >::value, void >::type *=nullptr) -> decltype(std::distance(Range.begin(), Range.end()))
Get the size of a range.
Definition: STLExtras.h:999
Definition: jni_util.h:136
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:49
Definition: jni_util.h:74
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE size_t size() const noexcept
size - Get the string size.
Definition: StringRef.h:138
Definition: jni_util.h:104
std::string & str()
Flushes the stream contents to the target string and returns the string&#39;s reference.
Definition: raw_ostream.h:498
Definition: jni_util.h:457
Definition: jni_util.h:604
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:149
LLVM_NODISCARD std::string str() const
str - Get the contents as an std::string.
Definition: StringRef.h:206