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