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