mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-23 01:21:42 +00:00
Adds new build system to repo (#1)
This commit is contained in:
committed by
Peter Johnson
parent
4f5b5b1377
commit
1243cf04ea
23
src/main/native/include/support/Base64.h
Normal file
23
src/main/native/include/support/Base64.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2015. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_SUPPORT_BASE64_H_
|
||||
#define WPIUTIL_SUPPORT_BASE64_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
#include "llvm/StringRef.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
std::size_t Base64Decode(llvm::StringRef encoded, std::string* plain);
|
||||
void Base64Encode(llvm::StringRef plain, std::string* encoded);
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_SUPPORT_BASE64_H_
|
||||
83
src/main/native/include/support/ConcurrentQueue.h
Normal file
83
src/main/native/include/support/ConcurrentQueue.h
Normal file
@@ -0,0 +1,83 @@
|
||||
//
|
||||
// Copyright (c) 2013 Juan Palacios juan.palacios.puyana@gmail.com
|
||||
// Subject to the BSD 2-Clause License
|
||||
// - see < http://opensource.org/licenses/BSD-2-Clause>
|
||||
//
|
||||
|
||||
#ifndef WPIUTIL_SUPPORT_CONCURRENT_QUEUE_H_
|
||||
#define WPIUTIL_SUPPORT_CONCURRENT_QUEUE_H_
|
||||
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
template <typename T>
|
||||
class ConcurrentQueue {
|
||||
public:
|
||||
bool empty() const {
|
||||
std::unique_lock<std::mutex> mlock(mutex_);
|
||||
return queue_.empty();
|
||||
}
|
||||
|
||||
typename std::queue<T>::size_type size() const {
|
||||
std::unique_lock<std::mutex> mlock(mutex_);
|
||||
return queue_.size();
|
||||
}
|
||||
|
||||
T pop() {
|
||||
std::unique_lock<std::mutex> mlock(mutex_);
|
||||
while (queue_.empty()) {
|
||||
cond_.wait(mlock);
|
||||
}
|
||||
auto item = std::move(queue_.front());
|
||||
queue_.pop();
|
||||
return item;
|
||||
}
|
||||
|
||||
void pop(T& item) {
|
||||
std::unique_lock<std::mutex> mlock(mutex_);
|
||||
while (queue_.empty()) {
|
||||
cond_.wait(mlock);
|
||||
}
|
||||
item = queue_.front();
|
||||
queue_.pop();
|
||||
}
|
||||
|
||||
void push(const T& item) {
|
||||
std::unique_lock<std::mutex> mlock(mutex_);
|
||||
queue_.push(item);
|
||||
mlock.unlock();
|
||||
cond_.notify_one();
|
||||
}
|
||||
|
||||
void push(T&& item) {
|
||||
std::unique_lock<std::mutex> mlock(mutex_);
|
||||
queue_.push(std::forward<T>(item));
|
||||
mlock.unlock();
|
||||
cond_.notify_one();
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void emplace(Args&&... args) {
|
||||
std::unique_lock<std::mutex> mlock(mutex_);
|
||||
queue_.emplace(std::forward<Args>(args)...);
|
||||
mlock.unlock();
|
||||
cond_.notify_one();
|
||||
}
|
||||
|
||||
ConcurrentQueue() = default;
|
||||
ConcurrentQueue(const ConcurrentQueue&) = delete;
|
||||
ConcurrentQueue& operator=(const ConcurrentQueue&) = delete;
|
||||
|
||||
private:
|
||||
std::queue<T> queue_;
|
||||
mutable std::mutex mutex_;
|
||||
std::condition_variable cond_;
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_SUPPORT_CONCURRENT_QUEUE_H_
|
||||
84
src/main/native/include/support/Logger.h
Normal file
84
src/main/native/include/support/Logger.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2015. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_SUPPORT_LOGGER_H_
|
||||
#define WPIUTIL_SUPPORT_LOGGER_H_
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "llvm/raw_ostream.h"
|
||||
#include "llvm/SmallString.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
enum LogLevel {
|
||||
WPI_LOG_CRITICAL = 50,
|
||||
WPI_LOG_ERROR = 40,
|
||||
WPI_LOG_WARNING = 30,
|
||||
WPI_LOG_INFO = 20,
|
||||
WPI_LOG_DEBUG = 10,
|
||||
WPI_LOG_DEBUG1 = 9,
|
||||
WPI_LOG_DEBUG2 = 8,
|
||||
WPI_LOG_DEBUG3 = 7,
|
||||
WPI_LOG_DEBUG4 = 6
|
||||
};
|
||||
|
||||
class Logger {
|
||||
public:
|
||||
typedef std::function<void(unsigned int level, const char* file,
|
||||
unsigned int line, const char* msg)> LogFunc;
|
||||
|
||||
void SetLogger(LogFunc func) { m_func = func; }
|
||||
|
||||
void set_min_level(unsigned int level) { m_min_level = level; }
|
||||
unsigned int min_level() const { return m_min_level; }
|
||||
|
||||
void Log(unsigned int level, const char* file, unsigned int line,
|
||||
const char* msg) {
|
||||
if (!m_func || level < m_min_level) return;
|
||||
m_func(level, file, line, msg);
|
||||
}
|
||||
|
||||
bool HasLogger() const { return m_func != nullptr; }
|
||||
|
||||
private:
|
||||
LogFunc m_func;
|
||||
unsigned int m_min_level = 20;
|
||||
};
|
||||
|
||||
#define WPI_LOG(logger_inst, level, x) \
|
||||
do { \
|
||||
::wpi::Logger& WPI_logger_ = logger_inst; \
|
||||
if (WPI_logger_.min_level() <= level && WPI_logger_.HasLogger()) { \
|
||||
llvm::SmallString<128> log_buf_; \
|
||||
llvm::raw_svector_ostream log_os_{log_buf_}; \
|
||||
log_os_ << x; \
|
||||
WPI_logger_.Log(level, __FILE__, __LINE__, log_buf_.c_str()); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define WPI_ERROR(inst, x) WPI_LOG(inst, ::wpi::WPI_LOG_ERROR, x)
|
||||
#define WPI_WARNING(inst, x) WPI_LOG(inst, ::wpi::WPI_LOG_WARNING, x)
|
||||
#define WPI_INFO(inst, x) WPI_LOG(inst, ::wpi::WPI_LOG_INFO, x)
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define WPI_DEBUG(inst, x) do {} while (0)
|
||||
#define WPI_DEBUG1(inst, x) do {} while (0)
|
||||
#define WPI_DEBUG2(inst, x) do {} while (0)
|
||||
#define WPI_DEBUG3(inst, x) do {} while (0)
|
||||
#define WPI_DEBUG4(inst, x) do {} while (0)
|
||||
#else
|
||||
#define WPI_DEBUG(inst, x) WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG, x)
|
||||
#define WPI_DEBUG1(inst, x) WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG1, x)
|
||||
#define WPI_DEBUG2(inst, x) WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG2, x)
|
||||
#define WPI_DEBUG3(inst, x) WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG3, x)
|
||||
#define WPI_DEBUG4(inst, x) WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG4, x)
|
||||
#endif
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_SUPPORT_LOGGER_H_
|
||||
132
src/main/native/include/support/SafeThread.h
Normal file
132
src/main/native/include/support/SafeThread.h
Normal file
@@ -0,0 +1,132 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2015. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_SUPPORT_SAFETHREAD_H_
|
||||
#define WPIUTIL_SUPPORT_SAFETHREAD_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
// Base class for SafeThreadOwner threads.
|
||||
class SafeThread {
|
||||
public:
|
||||
SafeThread() { m_active = true; }
|
||||
virtual ~SafeThread() = default;
|
||||
virtual void Main() = 0;
|
||||
|
||||
std::mutex m_mutex;
|
||||
std::atomic_bool m_active;
|
||||
std::condition_variable m_cond;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Non-template proxy base class for common proxy code.
|
||||
class SafeThreadProxyBase {
|
||||
public:
|
||||
SafeThreadProxyBase(SafeThread* thr) : m_thread(thr) {
|
||||
if (!m_thread) return;
|
||||
std::unique_lock<std::mutex>(m_thread->m_mutex).swap(m_lock);
|
||||
if (!m_thread->m_active) {
|
||||
m_lock.unlock();
|
||||
m_thread = nullptr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
explicit operator bool() const { return m_thread != nullptr; }
|
||||
std::unique_lock<std::mutex>& GetLock() { return m_lock; }
|
||||
|
||||
protected:
|
||||
SafeThread* m_thread;
|
||||
std::unique_lock<std::mutex> m_lock;
|
||||
};
|
||||
|
||||
// A proxy for SafeThread.
|
||||
// Also serves as a scoped lock on SafeThread::m_mutex.
|
||||
template <typename T>
|
||||
class SafeThreadProxy : public SafeThreadProxyBase {
|
||||
public:
|
||||
SafeThreadProxy(SafeThread* thr) : SafeThreadProxyBase(thr) {}
|
||||
T& operator*() const { return *static_cast<T*>(m_thread); }
|
||||
T* operator->() const { return static_cast<T*>(m_thread); }
|
||||
};
|
||||
|
||||
// Non-template owner base class for common owner code.
|
||||
class SafeThreadOwnerBase {
|
||||
public:
|
||||
void Stop();
|
||||
|
||||
SafeThreadOwnerBase() { m_thread = nullptr; }
|
||||
SafeThreadOwnerBase(const SafeThreadOwnerBase&) = delete;
|
||||
SafeThreadOwnerBase& operator=(const SafeThreadOwnerBase&) = delete;
|
||||
SafeThreadOwnerBase(SafeThreadOwnerBase&& other)
|
||||
: m_thread(other.m_thread.exchange(nullptr)) {}
|
||||
SafeThreadOwnerBase& operator=(SafeThreadOwnerBase other) {
|
||||
SafeThread* otherthr = other.m_thread.exchange(nullptr);
|
||||
SafeThread* curthr = m_thread.exchange(otherthr);
|
||||
other.m_thread.exchange(curthr); // other destructor will clean up
|
||||
return *this;
|
||||
}
|
||||
~SafeThreadOwnerBase() { Stop(); }
|
||||
|
||||
explicit operator bool() const { return m_thread.load(); }
|
||||
|
||||
protected:
|
||||
void Start(SafeThread* thr);
|
||||
SafeThread* GetThread() const { return m_thread.load(); }
|
||||
std::thread::native_handle_type GetNativeThreadHandle() const {
|
||||
return m_nativeHandle;
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic<SafeThread*> m_thread;
|
||||
std::atomic<std::thread::native_handle_type> m_nativeHandle;
|
||||
};
|
||||
|
||||
inline void SafeThreadOwnerBase::Start(SafeThread* thr) {
|
||||
SafeThread* curthr = nullptr;
|
||||
SafeThread* newthr = thr;
|
||||
if (!m_thread.compare_exchange_strong(curthr, newthr)) {
|
||||
delete newthr;
|
||||
return;
|
||||
}
|
||||
std::thread stdThread([=]() {
|
||||
newthr->Main();
|
||||
delete newthr;
|
||||
});
|
||||
m_nativeHandle = stdThread.native_handle();
|
||||
stdThread.detach();
|
||||
}
|
||||
|
||||
inline void SafeThreadOwnerBase::Stop() {
|
||||
SafeThread* thr = m_thread.exchange(nullptr);
|
||||
if (!thr) return;
|
||||
thr->m_active = false;
|
||||
thr->m_cond.notify_one();
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T>
|
||||
class SafeThreadOwner : public detail::SafeThreadOwnerBase {
|
||||
public:
|
||||
void Start() { Start(new T); }
|
||||
void Start(T* thr) { detail::SafeThreadOwnerBase::Start(thr); }
|
||||
|
||||
using Proxy = typename detail::SafeThreadProxy<T>;
|
||||
Proxy GetThread() const {
|
||||
return Proxy(detail::SafeThreadOwnerBase::GetThread());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_SUPPORT_SAFETHREAD_H_
|
||||
49
src/main/native/include/support/atomic_static.h
Normal file
49
src/main/native/include/support/atomic_static.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2015. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_SUPPORT_ATOMIC_STATIC_H_
|
||||
#define WPIUTIL_SUPPORT_ATOMIC_STATIC_H_
|
||||
|
||||
#if !defined(_MSC_VER) || (_MSC_VER >= 1900)
|
||||
|
||||
// Just use a local static. This is thread-safe per
|
||||
// http://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/
|
||||
|
||||
// Per https://msdn.microsoft.com/en-us/library/Hh567368.aspx "Magic Statics"
|
||||
// are supported in Visual Studio 2015 but not in earlier versions.
|
||||
#define ATOMIC_STATIC(cls, inst) static cls inst
|
||||
#define ATOMIC_STATIC_DECL(cls)
|
||||
#define ATOMIC_STATIC_INIT(cls)
|
||||
|
||||
#else
|
||||
// From http://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
|
||||
#define ATOMIC_STATIC(cls, inst) \
|
||||
cls* inst##tmp = m_instance.load(std::memory_order_acquire); \
|
||||
if (inst##tmp == nullptr) { \
|
||||
std::lock_guard<std::mutex> lock(m_instance_mutex); \
|
||||
inst##tmp = m_instance.load(std::memory_order_relaxed); \
|
||||
if (inst##tmp == nullptr) { \
|
||||
inst##tmp = new cls; \
|
||||
m_instance.store(inst##tmp, std::memory_order_release); \
|
||||
} \
|
||||
} \
|
||||
cls& inst = *inst##tmp
|
||||
|
||||
#define ATOMIC_STATIC_DECL(cls) \
|
||||
static std::atomic<cls*> m_instance; \
|
||||
static std::mutex m_instance_mutex;
|
||||
|
||||
#define ATOMIC_STATIC_INIT(cls) \
|
||||
std::atomic<cls*> cls::m_instance; \
|
||||
std::mutex cls::m_instance_mutex;
|
||||
|
||||
#endif
|
||||
|
||||
#endif // WPIUTIL_SUPPORT_ATOMIC_STATIC_H_
|
||||
33
src/main/native/include/support/deprecated.h
Normal file
33
src/main/native/include/support/deprecated.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2015. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef DEPRECATED_H_
|
||||
#define DEPRECATED_H_
|
||||
|
||||
// [[deprecated(msg)]] is a C++14 feature not supported by MSVC or GCC < 4.9.
|
||||
// We provide an equivalent warning implementation for those compilers here.
|
||||
#ifndef WPI_DEPRECATED
|
||||
#if defined(_MSC_VER)
|
||||
#define WPI_DEPRECATED(msg) __declspec(deprecated(msg))
|
||||
#elif defined(__GNUC__)
|
||||
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 8)
|
||||
#if __cplusplus > 201103L
|
||||
#define WPI_DEPRECATED(msg) [[deprecated(msg)]]
|
||||
#else
|
||||
#define WPI_DEPRECATED(msg) [[gnu::deprecated(msg)]]
|
||||
#endif
|
||||
#else
|
||||
#define WPI_DEPRECATED(msg) __attribute__((deprecated(msg)))
|
||||
#endif
|
||||
#elif __cplusplus > 201103L
|
||||
#define WPI_DEPRECATED(msg) [[deprecated(msg)]]
|
||||
#else
|
||||
#define WPI_DEPRECATED(msg) /*nothing*/
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // DEPRECATED_H_
|
||||
608
src/main/native/include/support/jni_util.h
Normal file
608
src/main/native/include/support/jni_util.h
Normal file
@@ -0,0 +1,608 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_SUPPORT_JNI_UTIL_H_
|
||||
#define WPIUTIL_SUPPORT_JNI_UTIL_H_
|
||||
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include "llvm/ArrayRef.h"
|
||||
#include "llvm/ConvertUTF.h"
|
||||
#include "llvm/raw_ostream.h"
|
||||
#include "llvm/SmallString.h"
|
||||
#include "llvm/SmallVector.h"
|
||||
#include "llvm/StringRef.h"
|
||||
#include "support/atomic_static.h"
|
||||
#include "support/SafeThread.h"
|
||||
|
||||
namespace wpi {
|
||||
namespace java {
|
||||
|
||||
// Gets a Java stack trace. This version also provides the last function
|
||||
// in the stack trace not starting with excludeFuncPrefix (useful for e.g.
|
||||
// finding the first user call to a series of library functions).
|
||||
template <const char* excludeFuncPrefix = nullptr>
|
||||
std::string GetJavaStackTrace(JNIEnv* env, std::string* func);
|
||||
|
||||
// Gets a Java stack trace.
|
||||
inline std::string GetJavaStackTrace(JNIEnv* env) {
|
||||
return GetJavaStackTrace(env, nullptr);
|
||||
}
|
||||
|
||||
// Finds a class and keep it as a global reference.
|
||||
// Use with caution, as the destructor does NOT call DeleteGlobalRef due
|
||||
// to potential shutdown issues with doing so.
|
||||
class JClass {
|
||||
public:
|
||||
JClass() = default;
|
||||
|
||||
JClass(JNIEnv* env, const char* name) {
|
||||
jclass local = env->FindClass(name);
|
||||
if (!local) return;
|
||||
m_cls = static_cast<jclass>(env->NewGlobalRef(local));
|
||||
env->DeleteLocalRef(local);
|
||||
}
|
||||
|
||||
void free(JNIEnv *env) {
|
||||
if (m_cls) env->DeleteGlobalRef(m_cls);
|
||||
m_cls = nullptr;
|
||||
}
|
||||
|
||||
explicit operator bool() const { return m_cls; }
|
||||
|
||||
operator jclass() const { return m_cls; }
|
||||
|
||||
protected:
|
||||
jclass m_cls = nullptr;
|
||||
};
|
||||
|
||||
// Container class for cleaning up Java local references.
|
||||
// The destructor calls DeleteLocalRef.
|
||||
template <typename T>
|
||||
class JLocal {
|
||||
public:
|
||||
JLocal(JNIEnv *env, T obj) : m_env(env), m_obj(obj) {}
|
||||
JLocal(const JLocal&) = delete;
|
||||
JLocal(JLocal&& oth) : m_env(oth.m_env), m_obj(oth.m_obj) {
|
||||
oth.m_obj = nullptr;
|
||||
}
|
||||
JLocal& operator=(const JLocal&) = delete;
|
||||
JLocal& operator=(JLocal&& oth) {
|
||||
m_env = oth.m_env;
|
||||
m_obj = oth.m_obj;
|
||||
oth.m_obj = nullptr;
|
||||
return *this;
|
||||
}
|
||||
~JLocal() {
|
||||
if (m_obj) m_env->DeleteLocalRef(m_obj);
|
||||
}
|
||||
operator T() { return m_obj; }
|
||||
T obj() { return m_obj; }
|
||||
|
||||
private:
|
||||
JNIEnv *m_env;
|
||||
T m_obj;
|
||||
};
|
||||
|
||||
//
|
||||
// Conversions from Java objects to C++
|
||||
//
|
||||
|
||||
// Java string (jstring) reference. The string is provided as UTF8.
|
||||
// This is not actually a reference, as it makes a copy of the string
|
||||
// characters, but it's named this way for consistency.
|
||||
class JStringRef {
|
||||
public:
|
||||
JStringRef(JNIEnv *env, jstring str) {
|
||||
if (str) {
|
||||
jsize size = env->GetStringLength(str);
|
||||
const jchar *chars = env->GetStringCritical(str, nullptr);
|
||||
if (chars) {
|
||||
llvm::convertUTF16ToUTF8String(llvm::makeArrayRef(chars, size), m_str);
|
||||
env->ReleaseStringCritical(str, chars);
|
||||
}
|
||||
} else {
|
||||
llvm::errs() << "JStringRef was passed a null pointer at \n"
|
||||
<< GetJavaStackTrace(env);
|
||||
}
|
||||
// Ensure str is null-terminated.
|
||||
m_str.push_back('\0');
|
||||
m_str.pop_back();
|
||||
}
|
||||
|
||||
operator llvm::StringRef() const { return m_str; }
|
||||
llvm::StringRef str() const { return m_str; }
|
||||
const char* c_str() const { return m_str.data(); }
|
||||
size_t size() const { return m_str.size(); }
|
||||
|
||||
private:
|
||||
llvm::SmallString<128> m_str;
|
||||
};
|
||||
|
||||
// Details for J*ArrayRef and CriticalJ*ArrayRef
|
||||
namespace detail {
|
||||
|
||||
template <typename C, typename T>
|
||||
class JArrayRefInner {};
|
||||
|
||||
// Specialization of JArrayRefBase to provide StringRef conversion.
|
||||
template <typename C>
|
||||
class JArrayRefInner<C, jbyte> {
|
||||
public:
|
||||
operator llvm::StringRef() const { return str(); }
|
||||
|
||||
llvm::StringRef str() const {
|
||||
auto arr = static_cast<const C *>(this)->array();
|
||||
if (arr.empty()) return llvm::StringRef{};
|
||||
return llvm::StringRef{reinterpret_cast<const char *>(arr.data()),
|
||||
arr.size()};
|
||||
}
|
||||
};
|
||||
|
||||
// Base class for J*ArrayRef and CriticalJ*ArrayRef
|
||||
template <typename T>
|
||||
class JArrayRefBase : public JArrayRefInner<JArrayRefBase<T>, T> {
|
||||
public:
|
||||
explicit operator bool() const { return this->m_elements != nullptr; }
|
||||
|
||||
operator llvm::ArrayRef<T>() const { return array(); }
|
||||
|
||||
llvm::ArrayRef<T> array() const {
|
||||
if (!this->m_elements) return llvm::ArrayRef<T>{};
|
||||
return llvm::ArrayRef<T>{this->m_elements, this->m_size};
|
||||
}
|
||||
|
||||
JArrayRefBase(const JArrayRefBase&) = delete;
|
||||
JArrayRefBase& operator=(const JArrayRefBase&) = delete;
|
||||
|
||||
JArrayRefBase(JArrayRefBase&& oth)
|
||||
: m_env(oth.m_env),
|
||||
m_jarr(oth.m_jarr),
|
||||
m_size(oth.m_size),
|
||||
m_elements(oth.m_elements) {
|
||||
oth.m_jarr = nullptr;
|
||||
oth.m_elements = nullptr;
|
||||
}
|
||||
|
||||
JArrayRefBase& operator=(JArrayRefBase&& oth) {
|
||||
this->m_env = oth.m_env;
|
||||
this->m_jarr = oth.m_jarr;
|
||||
this->m_size = oth.m_size;
|
||||
this->m_elements = oth.m_elements;
|
||||
oth.m_jarr = nullptr;
|
||||
oth.m_elements = nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
JArrayRefBase(JNIEnv *env, T* elements, size_t size) {
|
||||
this->m_env = env;
|
||||
this->m_jarr = nullptr;
|
||||
this->m_size = size;
|
||||
this->m_elements = elements;
|
||||
}
|
||||
|
||||
JArrayRefBase(JNIEnv *env, jarray jarr) {
|
||||
this->m_env = env;
|
||||
this->m_jarr = jarr;
|
||||
this->m_size = jarr ? env->GetArrayLength(jarr) : 0;
|
||||
this->m_elements = nullptr;
|
||||
}
|
||||
|
||||
JNIEnv *m_env;
|
||||
jarray m_jarr = nullptr;
|
||||
size_t m_size;
|
||||
T *m_elements;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// Java array / DirectBuffer reference.
|
||||
|
||||
#define WPI_JNI_JARRAYREF(T, F) \
|
||||
class J##F##ArrayRef : public detail::JArrayRefBase<T> { \
|
||||
public: \
|
||||
J##F##ArrayRef(JNIEnv* env, jobject bb, int len) \
|
||||
: detail::JArrayRefBase<T>( \
|
||||
env, \
|
||||
static_cast<T*>(bb ? env->GetDirectBufferAddress(bb) : nullptr), \
|
||||
len) { \
|
||||
if (!bb) \
|
||||
llvm::errs() << "JArrayRef was passed a null pointer at \n" \
|
||||
<< GetJavaStackTrace(env); \
|
||||
} \
|
||||
J##F##ArrayRef(JNIEnv* env, T##Array jarr) \
|
||||
: detail::JArrayRefBase<T>(env, jarr) { \
|
||||
if (jarr) \
|
||||
m_elements = env->Get##F##ArrayElements(jarr, nullptr); \
|
||||
else \
|
||||
llvm::errs() << "JArrayRef was passed a null pointer at \n" \
|
||||
<< GetJavaStackTrace(env); \
|
||||
} \
|
||||
~J##F##ArrayRef() { \
|
||||
if (m_jarr && m_elements) \
|
||||
m_env->Release##F##ArrayElements(static_cast<T##Array>(m_jarr), \
|
||||
m_elements, JNI_ABORT); \
|
||||
} \
|
||||
}; \
|
||||
\
|
||||
class CriticalJ##F##ArrayRef : public detail::JArrayRefBase<T> { \
|
||||
public: \
|
||||
CriticalJ##F##ArrayRef(JNIEnv* env, T##Array jarr) \
|
||||
: detail::JArrayRefBase<T>(env, jarr) { \
|
||||
if (jarr) \
|
||||
m_elements = \
|
||||
static_cast<T*>(env->GetPrimitiveArrayCritical(jarr, nullptr)); \
|
||||
else \
|
||||
llvm::errs() << "JArrayRef was passed a null pointer at \n" \
|
||||
<< GetJavaStackTrace(env); \
|
||||
} \
|
||||
~CriticalJ##F##ArrayRef() { \
|
||||
if (m_jarr && m_elements) \
|
||||
m_env->ReleasePrimitiveArrayCritical(m_jarr, m_elements, JNI_ABORT); \
|
||||
} \
|
||||
};
|
||||
|
||||
WPI_JNI_JARRAYREF(jboolean, Boolean)
|
||||
WPI_JNI_JARRAYREF(jbyte, Byte)
|
||||
WPI_JNI_JARRAYREF(jshort, Short)
|
||||
WPI_JNI_JARRAYREF(jint, Int)
|
||||
WPI_JNI_JARRAYREF(jlong, Long)
|
||||
WPI_JNI_JARRAYREF(jfloat, Float)
|
||||
WPI_JNI_JARRAYREF(jdouble, Double)
|
||||
|
||||
#undef WPI_JNI_JARRAYREF
|
||||
|
||||
//
|
||||
// Conversions from C++ to Java objects
|
||||
//
|
||||
|
||||
// Convert a UTF8 string into a jstring.
|
||||
inline jstring MakeJString(JNIEnv *env, llvm::StringRef str) {
|
||||
llvm::SmallVector<UTF16, 128> chars;
|
||||
llvm::convertUTF8ToUTF16String(str, chars);
|
||||
return env->NewString(chars.begin(), chars.size());
|
||||
}
|
||||
|
||||
// details for MakeJIntArray
|
||||
namespace detail {
|
||||
|
||||
// Slow path (get primitive array and set individual elements). This
|
||||
// is used if the input type is not an integer of the same size (note
|
||||
// signed/unsigned is ignored).
|
||||
template <typename T,
|
||||
bool = (std::is_integral<T>::value && sizeof(jint) == sizeof(T))>
|
||||
struct ConvertIntArray {
|
||||
static jintArray ToJava(JNIEnv *env, llvm::ArrayRef<T> arr) {
|
||||
jintArray jarr = env->NewIntArray(arr.size());
|
||||
if (!jarr) return nullptr;
|
||||
jint *elements =
|
||||
static_cast<jint *>(env->GetPrimitiveArrayCritical(jarr, nullptr));
|
||||
if (!elements) return nullptr;
|
||||
for (size_t i = 0; i < arr.size(); ++i)
|
||||
elements[i] = static_cast<jint>(arr[i]);
|
||||
env->ReleasePrimitiveArrayCritical(jarr, elements, 0);
|
||||
return jarr;
|
||||
}
|
||||
};
|
||||
|
||||
// Fast path (use SetIntArrayRegion)
|
||||
template <typename T>
|
||||
struct ConvertIntArray<T, true> {
|
||||
static jintArray ToJava(JNIEnv *env, llvm::ArrayRef<T> arr) {
|
||||
jintArray jarr = env->NewIntArray(arr.size());
|
||||
if (!jarr) return nullptr;
|
||||
env->SetIntArrayRegion(jarr, 0, arr.size(),
|
||||
reinterpret_cast<const jint*>(arr.data()));
|
||||
return jarr;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// Convert an ArrayRef to a jintArray.
|
||||
template <typename T>
|
||||
inline jintArray MakeJIntArray(JNIEnv *env, llvm::ArrayRef<T> arr) {
|
||||
return detail::ConvertIntArray<T>::ToJava(env, arr);
|
||||
}
|
||||
|
||||
// Convert a SmallVector to a jintArray. This is required in addition to
|
||||
// ArrayRef because template resolution occurs prior to implicit conversions.
|
||||
template <typename T>
|
||||
inline jintArray MakeJIntArray(JNIEnv *env,
|
||||
const llvm::SmallVectorImpl<T> &arr) {
|
||||
return detail::ConvertIntArray<T>::ToJava(env, arr);
|
||||
}
|
||||
|
||||
// Convert a std::vector to a jintArray. This is required in addition to
|
||||
// ArrayRef because template resolution occurs prior to implicit conversions.
|
||||
template <typename T>
|
||||
inline jintArray MakeJIntArray(JNIEnv *env, const std::vector<T> &arr) {
|
||||
return detail::ConvertIntArray<T>::ToJava(env, arr);
|
||||
}
|
||||
|
||||
// Convert a StringRef into a jbyteArray.
|
||||
inline jbyteArray MakeJByteArray(JNIEnv *env, llvm::StringRef str) {
|
||||
jbyteArray jarr = env->NewByteArray(str.size());
|
||||
if (!jarr) return nullptr;
|
||||
env->SetByteArrayRegion(jarr, 0, str.size(),
|
||||
reinterpret_cast<const jbyte *>(str.data()));
|
||||
return jarr;
|
||||
}
|
||||
|
||||
// Convert an array of integers into a jbooleanArray.
|
||||
inline jbooleanArray MakeJBooleanArray(JNIEnv *env, llvm::ArrayRef<int> arr)
|
||||
{
|
||||
jbooleanArray jarr = env->NewBooleanArray(arr.size());
|
||||
if (!jarr) return nullptr;
|
||||
jboolean *elements =
|
||||
static_cast<jboolean*>(env->GetPrimitiveArrayCritical(jarr, nullptr));
|
||||
if (!elements) return nullptr;
|
||||
for (size_t i = 0; i < arr.size(); ++i)
|
||||
elements[i] = arr[i] ? JNI_TRUE : JNI_FALSE;
|
||||
env->ReleasePrimitiveArrayCritical(jarr, elements, 0);
|
||||
return jarr;
|
||||
}
|
||||
|
||||
// Convert an array of booleans into a jbooleanArray.
|
||||
inline jbooleanArray MakeJBooleanArray(JNIEnv *env, llvm::ArrayRef<bool> arr)
|
||||
{
|
||||
jbooleanArray jarr = env->NewBooleanArray(arr.size());
|
||||
if (!jarr) return nullptr;
|
||||
jboolean *elements =
|
||||
static_cast<jboolean*>(env->GetPrimitiveArrayCritical(jarr, nullptr));
|
||||
if (!elements) return nullptr;
|
||||
for (size_t i = 0; i < arr.size(); ++i)
|
||||
elements[i] = arr[i] ? JNI_TRUE : JNI_FALSE;
|
||||
env->ReleasePrimitiveArrayCritical(jarr, elements, 0);
|
||||
return jarr;
|
||||
}
|
||||
|
||||
// Other MakeJ*Array conversions.
|
||||
|
||||
#define WPI_JNI_MAKEJARRAY(T, F) \
|
||||
inline T##Array MakeJ##F##Array(JNIEnv *env, llvm::ArrayRef<T> arr) { \
|
||||
T##Array jarr = env->New##F##Array(arr.size()); \
|
||||
if (!jarr) return nullptr; \
|
||||
env->Set##F##ArrayRegion(jarr, 0, arr.size(), arr.data()); \
|
||||
return jarr; \
|
||||
}
|
||||
|
||||
WPI_JNI_MAKEJARRAY(jboolean, Boolean)
|
||||
WPI_JNI_MAKEJARRAY(jbyte, Byte)
|
||||
WPI_JNI_MAKEJARRAY(jshort, Short)
|
||||
WPI_JNI_MAKEJARRAY(jlong, Long)
|
||||
WPI_JNI_MAKEJARRAY(jfloat, Float)
|
||||
WPI_JNI_MAKEJARRAY(jdouble, Double)
|
||||
|
||||
#undef WPI_JNI_MAKEJARRAY
|
||||
|
||||
// Convert an array of std::string into a jarray of jstring.
|
||||
inline jobjectArray MakeJStringArray(JNIEnv *env,
|
||||
llvm::ArrayRef<std::string> arr) {
|
||||
static JClass stringCls{env, "java/lang/String"};
|
||||
if (!stringCls) return nullptr;
|
||||
jobjectArray jarr = env->NewObjectArray(arr.size(), stringCls, nullptr);
|
||||
if (!jarr) return nullptr;
|
||||
for (std::size_t i = 0; i < arr.size(); ++i) {
|
||||
JLocal<jstring> elem{env, MakeJString(env, arr[i])};
|
||||
env->SetObjectArrayElement(jarr, i, elem.obj());
|
||||
}
|
||||
return jarr;
|
||||
}
|
||||
|
||||
// Generic callback thread implementation.
|
||||
//
|
||||
// JNI's AttachCurrentThread() creates a Java Thread object on every
|
||||
// invocation, which is both time inefficient and causes issues with Eclipse
|
||||
// (which tries to keep a thread list up-to-date and thus gets swamped).
|
||||
//
|
||||
// Instead, this class attaches just once. When a hardware notification
|
||||
// occurs, a condition variable wakes up this thread and this thread actually
|
||||
// makes the call into Java.
|
||||
//
|
||||
// The template parameter T is the message being passed to the callback, but
|
||||
// also needs to provide the following functions:
|
||||
// static JavaVM* GetJVM();
|
||||
// static const char* GetName();
|
||||
// void CallJava(JNIEnv *env, jobject func, jmethodID mid);
|
||||
//
|
||||
// When creating this, ATOMIC_STATIC_INIT() needs to be performed on the
|
||||
// templated class as well.
|
||||
template <typename T>
|
||||
class JCallbackThread : public SafeThread {
|
||||
public:
|
||||
void Main();
|
||||
|
||||
std::queue<T> m_queue;
|
||||
jobject m_func = nullptr;
|
||||
jmethodID m_mid;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class JCallbackManager : public SafeThreadOwner<JCallbackThread<T>> {
|
||||
public:
|
||||
void SetFunc(JNIEnv* env, jobject func, jmethodID mid);
|
||||
|
||||
template <typename... Args>
|
||||
void Send(Args&&... args);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void JCallbackManager<T>::SetFunc(JNIEnv* env, jobject func, jmethodID mid) {
|
||||
auto thr = this->GetThread();
|
||||
if (!thr) return;
|
||||
// free global reference
|
||||
if (thr->m_func) env->DeleteGlobalRef(thr->m_func);
|
||||
// create global reference
|
||||
thr->m_func = env->NewGlobalRef(func);
|
||||
thr->m_mid = mid;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename... Args>
|
||||
void JCallbackManager<T>::Send(Args&&... args) {
|
||||
auto thr = this->GetThread();
|
||||
if (!thr) return;
|
||||
thr->m_queue.emplace(std::forward<Args>(args)...);
|
||||
thr->m_cond.notify_one();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void JCallbackThread<T>::Main() {
|
||||
JNIEnv *env;
|
||||
JavaVMAttachArgs args;
|
||||
args.version = JNI_VERSION_1_2;
|
||||
args.name = const_cast<char*>(T::GetName());
|
||||
args.group = nullptr;
|
||||
jint rs = T::GetJVM()->AttachCurrentThreadAsDaemon((void**)&env, &args);
|
||||
if (rs != JNI_OK) return;
|
||||
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
while (m_active) {
|
||||
m_cond.wait(lock, [&] { return !(m_active && m_queue.empty()); });
|
||||
if (!m_active) break;
|
||||
while (!m_queue.empty()) {
|
||||
if (!m_active) break;
|
||||
auto item = std::move(m_queue.front());
|
||||
m_queue.pop();
|
||||
auto func = m_func;
|
||||
auto mid = m_mid;
|
||||
lock.unlock(); // don't hold mutex during callback execution
|
||||
item.CallJava(env, func, mid);
|
||||
if (env->ExceptionCheck()) {
|
||||
env->ExceptionDescribe();
|
||||
env->ExceptionClear();
|
||||
}
|
||||
lock.lock();
|
||||
}
|
||||
}
|
||||
|
||||
JavaVM* jvm = T::GetJVM();
|
||||
if (jvm) jvm->DetachCurrentThread();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class JSingletonCallbackManager : public JCallbackManager<T> {
|
||||
public:
|
||||
static JSingletonCallbackManager<T>& GetInstance() {
|
||||
ATOMIC_STATIC(JSingletonCallbackManager<T>, instance);
|
||||
return instance;
|
||||
}
|
||||
|
||||
private:
|
||||
ATOMIC_STATIC_DECL(JSingletonCallbackManager<T>)
|
||||
};
|
||||
|
||||
template<const char* excludeFuncPrefix>
|
||||
std::string GetJavaStackTrace(JNIEnv* env, std::string* func) {
|
||||
// create a throwable
|
||||
static JClass throwableCls(env, "java/lang/Throwable");
|
||||
if (!throwableCls) return "";
|
||||
static jmethodID constructorId = nullptr;
|
||||
if (!constructorId)
|
||||
constructorId = env->GetMethodID(throwableCls, "<init>", "()V");
|
||||
JLocal<jobject> throwable(env, env->NewObject(throwableCls, constructorId));
|
||||
|
||||
// retrieve information from the exception.
|
||||
// get method id
|
||||
// getStackTrace returns an array of StackTraceElement
|
||||
static jmethodID getStackTraceId = nullptr;
|
||||
if (!getStackTraceId)
|
||||
getStackTraceId = env->GetMethodID(throwableCls, "getStackTrace",
|
||||
"()[Ljava/lang/StackTraceElement;");
|
||||
|
||||
// call getStackTrace
|
||||
JLocal<jobjectArray> stackTrace(
|
||||
env, static_cast<jobjectArray>(
|
||||
env->CallObjectMethod(throwable, getStackTraceId)));
|
||||
|
||||
if (!stackTrace) return "";
|
||||
|
||||
// get length of the array
|
||||
jsize stackTraceLength = env->GetArrayLength(stackTrace);
|
||||
|
||||
// get toString methodId of StackTraceElement class
|
||||
static JClass stackTraceElementCls(env, "java/lang/StackTraceElement");
|
||||
if (!stackTraceElementCls) return "";
|
||||
static jmethodID toStringId = nullptr;
|
||||
if (!toStringId)
|
||||
toStringId = env->GetMethodID(stackTraceElementCls, "toString",
|
||||
"()Ljava/lang/String;");
|
||||
|
||||
bool haveLoc = false;
|
||||
std::string buf;
|
||||
llvm::raw_string_ostream oss(buf);
|
||||
for (jsize i = 0; i < stackTraceLength; i++) {
|
||||
// add the result of toString method of each element in the result
|
||||
JLocal<jobject> curStackTraceElement(
|
||||
env, env->GetObjectArrayElement(stackTrace, i));
|
||||
|
||||
// call to string on the object
|
||||
JLocal<jstring> stackElementString(
|
||||
env, static_cast<jstring>(
|
||||
env->CallObjectMethod(curStackTraceElement, toStringId)));
|
||||
|
||||
if (!stackElementString) return "";
|
||||
|
||||
// add a line to res
|
||||
JStringRef elem(env, stackElementString);
|
||||
oss << elem << '\n';
|
||||
|
||||
if (func) {
|
||||
// func is caller of immediate caller (if there was one)
|
||||
// or, if we see it, the first user function
|
||||
if (i == 1)
|
||||
*func = elem.str();
|
||||
else if (i > 1 && !haveLoc && excludeFuncPrefix != nullptr &&
|
||||
!elem.str().startswith(excludeFuncPrefix)) {
|
||||
*func = elem.str();
|
||||
haveLoc = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
// Finds an exception class and keep it as a global reference.
|
||||
// Similar to JClass, but provides Throw methods.
|
||||
// Use with caution, as the destructor does NOT call DeleteGlobalRef due
|
||||
// to potential shutdown issues with doing so.
|
||||
class JException : public JClass {
|
||||
public:
|
||||
JException() = default;
|
||||
JException(JNIEnv* env, const char* name) : JClass(env, name) {
|
||||
if (m_cls)
|
||||
m_constructor =
|
||||
env->GetMethodID(m_cls, "<init>", "(Ljava/lang/String;)V");
|
||||
}
|
||||
|
||||
void Throw(JNIEnv* env, jstring msg) {
|
||||
jobject exception = env->NewObject(m_cls, m_constructor, msg);
|
||||
env->Throw(static_cast<jthrowable>(exception));
|
||||
}
|
||||
|
||||
void Throw(JNIEnv* env, llvm::StringRef msg) {
|
||||
Throw(env, MakeJString(env, msg));
|
||||
}
|
||||
|
||||
explicit operator bool() const { return m_constructor; }
|
||||
|
||||
private:
|
||||
jmethodID m_constructor = nullptr;
|
||||
};
|
||||
|
||||
} // namespace java
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_SUPPORT_JNI_UTIL_H_
|
||||
26
src/main/native/include/support/leb128.h
Normal file
26
src/main/native/include/support/leb128.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2015. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_SUPPORT_LEB128_H_
|
||||
#define WPIUTIL_SUPPORT_LEB128_H_
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "llvm/SmallVector.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
class raw_istream;
|
||||
|
||||
std::size_t SizeUleb128(unsigned long val);
|
||||
std::size_t WriteUleb128(llvm::SmallVectorImpl<char>& dest, unsigned long val);
|
||||
std::size_t ReadUleb128(const char* addr, unsigned long* ret);
|
||||
bool ReadUleb128(raw_istream& is, unsigned long* ret);
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_SUPPORT_LEB128_H_
|
||||
99
src/main/native/include/support/raw_istream.h
Normal file
99
src/main/native/include/support/raw_istream.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2015. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_SUPPORT_RAW_ISTREAM_H_
|
||||
#define WPIUTIL_SUPPORT_RAW_ISTREAM_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
class raw_istream {
|
||||
public:
|
||||
raw_istream() = default;
|
||||
virtual ~raw_istream() = default;
|
||||
|
||||
raw_istream& read(char& c) {
|
||||
read_impl(&c, 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_istream& read(unsigned char& c) {
|
||||
read_impl(&c, 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_istream& read(signed char& c) {
|
||||
read_impl(&c, 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_istream& read(void* data, std::size_t len) {
|
||||
read_impl(data, len);
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::size_t readsome(void* data, std::size_t len) {
|
||||
std::size_t readlen = std::min(in_avail(), len);
|
||||
if (readlen == 0) return 0;
|
||||
read_impl(data, readlen);
|
||||
return readlen;
|
||||
};
|
||||
|
||||
virtual void close() = 0;
|
||||
virtual std::size_t in_avail() const = 0;
|
||||
|
||||
bool has_error() const { return m_error; }
|
||||
void clear_error() { m_error = false; }
|
||||
|
||||
raw_istream(const raw_istream&) = delete;
|
||||
raw_istream& operator=(const raw_istream&) = delete;
|
||||
|
||||
protected:
|
||||
void error_detected() { m_error = true; }
|
||||
|
||||
private:
|
||||
virtual void read_impl(void* data, std::size_t len) = 0;
|
||||
|
||||
bool m_error = false;
|
||||
};
|
||||
|
||||
class raw_mem_istream : public raw_istream {
|
||||
public:
|
||||
raw_mem_istream(const char* mem, std::size_t len) : m_cur(mem), m_left(len) {}
|
||||
void close() override;
|
||||
std::size_t in_avail() const override;
|
||||
|
||||
private:
|
||||
void read_impl(void* data, std::size_t len) override;
|
||||
|
||||
const char* m_cur;
|
||||
std::size_t m_left;
|
||||
};
|
||||
|
||||
class raw_fd_istream : public raw_istream {
|
||||
public:
|
||||
raw_fd_istream(int fd, bool shouldClose, std::size_t bufSize = 4096);
|
||||
~raw_fd_istream() override;
|
||||
void close() override;
|
||||
std::size_t in_avail() const override;
|
||||
|
||||
private:
|
||||
void read_impl(void* data, std::size_t len) override;
|
||||
|
||||
char* m_buf;
|
||||
char* m_cur;
|
||||
char* m_end;
|
||||
std::size_t m_bufSize;
|
||||
int m_fd;
|
||||
bool m_shouldClose;
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_SUPPORT_RAW_ISTREAM_H_
|
||||
34
src/main/native/include/support/raw_socket_istream.h
Normal file
34
src/main/native/include/support/raw_socket_istream.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2015. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_SUPPORT_RAW_SOCKET_ISTREAM_H_
|
||||
#define WPIUTIL_SUPPORT_RAW_SOCKET_ISTREAM_H_
|
||||
|
||||
#include "support/raw_istream.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
class NetworkStream;
|
||||
|
||||
class raw_socket_istream : public raw_istream {
|
||||
public:
|
||||
explicit raw_socket_istream(NetworkStream& stream, int timeout = 0)
|
||||
: m_stream(stream), m_timeout(timeout) {}
|
||||
|
||||
void close() override;
|
||||
std::size_t in_avail() const override;
|
||||
|
||||
private:
|
||||
void read_impl(void* data, std::size_t len) override;
|
||||
|
||||
NetworkStream& m_stream;
|
||||
int m_timeout;
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_SUPPORT_RAW_SOCKET_ISTREAM_H_
|
||||
42
src/main/native/include/support/raw_socket_ostream.h
Normal file
42
src/main/native/include/support/raw_socket_ostream.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_SUPPORT_RAW_SOCKET_OSTREAM_H_
|
||||
#define WPIUTIL_SUPPORT_RAW_SOCKET_OSTREAM_H_
|
||||
|
||||
#include "llvm/raw_ostream.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
class NetworkStream;
|
||||
|
||||
class raw_socket_ostream : public llvm::raw_ostream {
|
||||
public:
|
||||
raw_socket_ostream(NetworkStream& stream, bool shouldClose)
|
||||
: m_stream(stream), m_shouldClose(shouldClose) {}
|
||||
~raw_socket_ostream();
|
||||
|
||||
void close();
|
||||
|
||||
bool has_error() const { return m_error; }
|
||||
void clear_error() { m_error = false; }
|
||||
|
||||
protected:
|
||||
void error_detected() { m_error = true; }
|
||||
|
||||
private:
|
||||
void write_impl(const char* data, std::size_t len) override;
|
||||
uint64_t current_pos() const override;
|
||||
|
||||
NetworkStream& m_stream;
|
||||
bool m_error = false;
|
||||
bool m_shouldClose;
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_SUPPORT_RAW_SOCKET_OSTREAM_H_
|
||||
28
src/main/native/include/support/timestamp.h
Normal file
28
src/main/native/include/support/timestamp.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2015. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
#ifndef WPIUTIL_SUPPORT_TIMESTAMP_H_
|
||||
#define WPIUTIL_SUPPORT_TIMESTAMP_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
unsigned long long WPI_Now(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace wpi {
|
||||
|
||||
unsigned long long Now();
|
||||
|
||||
} // namespace wpi
|
||||
#endif
|
||||
|
||||
#endif // WPIUTIL_SUPPORT_TIMESTAMP_H_
|
||||
Reference in New Issue
Block a user