Prepare wpiutil for merge into allwpilib.

This commit is contained in:
Peter Johnson
2017-12-20 19:26:48 -08:00
parent 71d06a1a20
commit 0f947613a9
224 changed files with 0 additions and 354 deletions

View File

@@ -0,0 +1,40 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2015-2018 FIRST. 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 llvm {
template <typename T>
class SmallVectorImpl;
class raw_ostream;
} // namespace llvm
namespace wpi {
size_t Base64Decode(llvm::raw_ostream& os, llvm::StringRef encoded);
size_t Base64Decode(llvm::StringRef encoded, std::string* plain);
llvm::StringRef Base64Decode(llvm::StringRef encoded, size_t* num_read,
llvm::SmallVectorImpl<char>& buf);
void Base64Encode(llvm::raw_ostream& os, llvm::StringRef plain);
void Base64Encode(llvm::StringRef plain, std::string* encoded);
llvm::StringRef Base64Encode(llvm::StringRef plain,
llvm::SmallVectorImpl<char>& buf);
} // namespace wpi
#endif // WPIUTIL_SUPPORT_BASE64_H_

View File

@@ -0,0 +1,85 @@
//
// 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_CONCURRENTQUEUE_H_
#define WPIUTIL_SUPPORT_CONCURRENTQUEUE_H_
#include <queue>
#include <thread>
#include <utility>
#include "support/condition_variable.h"
#include "support/mutex.h"
namespace wpi {
template <typename T>
class ConcurrentQueue {
public:
bool empty() const {
std::unique_lock<wpi::mutex> mlock(mutex_);
return queue_.empty();
}
typename std::queue<T>::size_type size() const {
std::unique_lock<wpi::mutex> mlock(mutex_);
return queue_.size();
}
T pop() {
std::unique_lock<wpi::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<wpi::mutex> mlock(mutex_);
while (queue_.empty()) {
cond_.wait(mlock);
}
item = queue_.front();
queue_.pop();
}
void push(const T& item) {
std::unique_lock<wpi::mutex> mlock(mutex_);
queue_.push(item);
mlock.unlock();
cond_.notify_one();
}
void push(T&& item) {
std::unique_lock<wpi::mutex> mlock(mutex_);
queue_.push(std::forward<T>(item));
mlock.unlock();
cond_.notify_one();
}
template <typename... Args>
void emplace(Args&&... args) {
std::unique_lock<wpi::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 wpi::mutex mutex_;
wpi::condition_variable cond_;
};
} // namespace wpi
#endif // WPIUTIL_SUPPORT_CONCURRENTQUEUE_H_

View File

@@ -0,0 +1,150 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 FIRST. 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_HTTPUTIL_H_
#define WPIUTIL_SUPPORT_HTTPUTIL_H_
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "llvm/ArrayRef.h"
#include "llvm/SmallString.h"
#include "llvm/SmallVector.h"
#include "llvm/StringMap.h"
#include "llvm/StringRef.h"
#include "llvm/Twine.h"
#include "support/raw_istream.h"
#include "support/raw_socket_istream.h"
#include "support/raw_socket_ostream.h"
#include "tcpsockets/NetworkStream.h"
namespace wpi {
// Unescape a %xx-encoded URI.
// @param buf Buffer for output
// @param error Set to true if an error occurred
// @return Escaped string
llvm::StringRef UnescapeURI(const llvm::Twine& str,
llvm::SmallVectorImpl<char>& buf, bool* error);
// Escape a string with %xx-encoding.
// @param buf Buffer for output
// @param spacePlus If true, encodes spaces to '+' rather than "%20"
// @return Escaped string
llvm::StringRef EscapeURI(const llvm::Twine& str,
llvm::SmallVectorImpl<char>& buf,
bool spacePlus = true);
// Parse a set of HTTP headers. Saves just the Content-Type and Content-Length
// fields.
// @param is Input stream
// @param contentType If not null, Content-Type contents are saved here.
// @param contentLength If not null, Content-Length contents are saved here.
// @return False if error occurred in input stream
bool ParseHttpHeaders(wpi::raw_istream& is,
llvm::SmallVectorImpl<char>* contentType,
llvm::SmallVectorImpl<char>* contentLength);
// Look for a MIME multi-part boundary. On return, the input stream will
// be located at the character following the boundary (usually "\r\n").
// @param is Input stream
// @param boundary Boundary string to scan for (not including "--" prefix)
// @param saveBuf If not null, all scanned characters up to but not including
// the boundary are saved to this string
// @return False if error occurred on input stream, true if boundary found.
bool FindMultipartBoundary(wpi::raw_istream& is, llvm::StringRef boundary,
std::string* saveBuf);
class HttpLocation {
public:
HttpLocation() = default;
HttpLocation(const llvm::Twine& url_, bool* error, std::string* errorMsg);
std::string url; // retain copy
std::string user; // unescaped
std::string password; // unescaped
std::string host;
int port;
std::string path; // escaped, not including leading '/'
std::vector<std::pair<std::string, std::string>> params; // unescaped
std::string fragment;
};
class HttpRequest {
public:
HttpRequest() = default;
explicit HttpRequest(const HttpLocation& loc)
: host{loc.host}, port{loc.port} {
SetPath(loc.path, loc.params);
SetAuth(loc);
}
template <typename T>
HttpRequest(const HttpLocation& loc, const T& extraParams);
HttpRequest(const HttpLocation& loc, llvm::StringRef path_)
: host{loc.host}, port{loc.port}, path{path_} {
SetAuth(loc);
}
template <typename T>
HttpRequest(const HttpLocation& loc, llvm::StringRef path_, const T& params)
: host{loc.host}, port{loc.port} {
SetPath(path_, params);
SetAuth(loc);
}
llvm::SmallString<128> host;
int port;
std::string auth;
llvm::SmallString<128> path;
private:
void SetAuth(const HttpLocation& loc);
template <typename T>
void SetPath(llvm::StringRef path_, const T& params);
template <typename T>
static llvm::StringRef GetFirst(const T& elem) {
return elem.first;
}
template <typename T>
static llvm::StringRef GetFirst(const llvm::StringMapEntry<T>& elem) {
return elem.getKey();
}
template <typename T>
static llvm::StringRef GetSecond(const T& elem) {
return elem.second;
}
};
class HttpConnection {
public:
HttpConnection(std::unique_ptr<wpi::NetworkStream> stream_, int timeout)
: stream{std::move(stream_)}, is{*stream, timeout}, os{*stream, true} {}
bool Handshake(const HttpRequest& request, std::string* warnMsg);
std::unique_ptr<wpi::NetworkStream> stream;
wpi::raw_socket_istream is;
wpi::raw_socket_ostream os;
// Valid after Handshake() is successful
llvm::SmallString<64> contentType;
llvm::SmallString<64> contentLength;
explicit operator bool() const { return stream && !is.has_error(); }
};
} // namespace wpi
#include "HttpUtil.inl"
#endif // WPIUTIL_SUPPORT_HTTPUTIL_H_

View File

@@ -0,0 +1,48 @@
/*----------------------------------------------------------------------------*/
/* 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_HTTPUTIL_INL_
#define WPIUTIL_SUPPORT_HTTPUTIL_INL_
namespace wpi {
template <typename T>
HttpRequest::HttpRequest(const HttpLocation& loc, const T& extraParams)
: host{loc.host}, port{loc.port} {
llvm::SmallVector<std::pair<llvm::StringRef, llvm::StringRef>, 8> params;
for (const auto& p : loc.params)
params.emplace_back(std::make_pair(GetFirst(p), GetSecond(p)));
for (const auto& p : extraParams)
params.emplace_back(std::make_pair(GetFirst(p), GetSecond(p)));
SetPath(loc.path, params);
SetAuth(loc);
}
template <typename T>
void HttpRequest::SetPath(llvm::StringRef path_, const T& params) {
// Build location including query string
llvm::raw_svector_ostream pathOs{path};
pathOs << path_;
bool first = true;
for (const auto& param : params) {
if (first) {
pathOs << '?';
first = false;
} else {
pathOs << '&';
}
llvm::SmallString<64> escapeBuf;
pathOs << EscapeURI(GetFirst(param), escapeBuf);
if (!GetSecond(param).empty()) {
pathOs << '=' << EscapeURI(GetSecond(param), escapeBuf);
}
}
}
} // namespace wpi
#endif // WPIUTIL_SUPPORT_HTTPUTIL_INL_

View File

@@ -0,0 +1,100 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2015-2018 FIRST. 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/SmallString.h"
#include "llvm/raw_ostream.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;
Logger() = default;
explicit Logger(const LogFunc& func) : m_func(func) {}
Logger(const LogFunc& func, unsigned int min_level)
: m_func(func), m_min_level(min_level) {}
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_

View File

@@ -0,0 +1,133 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2015-2018 FIRST. 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 <thread>
#include "support/condition_variable.h"
#include "support/mutex.h"
namespace wpi {
// Base class for SafeThreadOwner threads.
class SafeThread {
public:
SafeThread() { m_active = true; }
virtual ~SafeThread() = default;
virtual void Main() = 0;
wpi::mutex m_mutex;
std::atomic_bool m_active;
wpi::condition_variable m_cond;
};
namespace detail {
// Non-template proxy base class for common proxy code.
class SafeThreadProxyBase {
public:
explicit SafeThreadProxyBase(SafeThread* thr) : m_thread(thr) {
if (!m_thread) return;
m_lock = std::unique_lock<wpi::mutex>(m_thread->m_mutex);
if (!m_thread->m_active) {
m_lock.unlock();
m_thread = nullptr;
return;
}
}
explicit operator bool() const { return m_thread != nullptr; }
std::unique_lock<wpi::mutex>& GetLock() { return m_lock; }
protected:
SafeThread* m_thread;
std::unique_lock<wpi::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:
explicit 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_

View File

@@ -0,0 +1,67 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017-2018 FIRST. 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_UIDVECTOR_H_
#define WPIUTIL_SUPPORT_UIDVECTOR_H_
#include <utility>
#include <vector>
namespace wpi {
// Vector which provides an integrated freelist for removal and reuse of
// individual elements.
// @tparam T element type; must be default-constructible and evaluate in
// boolean context to false when "empty"
// @tparam reuse_threshold how many free elements to store up before starting
// to recycle them
template <typename T, typename std::vector<T>::size_type reuse_threshold>
class UidVector {
public:
typedef typename std::vector<T>::size_type size_type;
bool empty() const { return m_active_count == 0; }
size_type size() const { return m_vector.size(); }
T& operator[](size_type i) { return m_vector[i]; }
const T& operator[](size_type i) const { return m_vector[i]; }
// Add a new T to the vector. If there are elements on the freelist,
// reuses the last one; otherwise adds to the end of the vector.
// Returns the resulting element index.
template <class... Args>
size_type emplace_back(Args&&... args) {
size_type uid;
if (m_free.size() < reuse_threshold) {
uid = m_vector.size();
m_vector.emplace_back(std::forward<Args>(args)...);
} else {
uid = m_free.front();
m_free.erase(m_free.begin());
m_vector[uid] = T(std::forward<Args>(args)...);
}
++m_active_count;
return uid;
}
// Removes the identified element by replacing it with a default-constructed
// one. The element is added to the freelist for later reuse.
void erase(size_type uid) {
if (uid >= m_vector.size() || !m_vector[uid]) return;
m_free.push_back(uid);
m_vector[uid] = T();
--m_active_count;
}
private:
std::vector<T> m_vector;
std::vector<size_type> m_free;
size_type m_active_count{0};
};
} // namespace wpi
#endif // WPIUTIL_SUPPORT_UIDVECTOR_H_

View File

@@ -0,0 +1,49 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2015-2018 FIRST. 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_

View File

@@ -0,0 +1,22 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017-2018 FIRST. 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. */
/*----------------------------------------------------------------------------*/
#pragma once
#include <condition_variable>
#include "priority_condition_variable.h"
namespace wpi {
#ifdef WPI_HAVE_PRIORITY_CONDITION_VARIABLE
using condition_variable = priority_condition_variable;
#else
using condition_variable = ::std::condition_variable;
#endif
} // namespace wpi

View File

@@ -0,0 +1,33 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2015-2018 FIRST. 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_DEPRECATED_H_
#define WPIUTIL_SUPPORT_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 // WPIUTIL_SUPPORT_DEPRECATED_H_

View File

@@ -0,0 +1,25 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017-2018 FIRST. 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_HOSTNAME_H_
#define WPIUTIL_SUPPORT_HOSTNAME_H_
#include <string>
#include "llvm/StringRef.h"
namespace llvm {
template <typename T>
class SmallVectorImpl;
} // namespace llvm
namespace wpi {
std::string GetHostname();
llvm::StringRef GetHostname(llvm::SmallVectorImpl<char>& name);
} // namespace wpi
#endif // WPIUTIL_SUPPORT_HOSTNAME_H_

View File

@@ -0,0 +1,615 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 FIRST. 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 <jni.h>
#include <queue>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
#include "llvm/ArrayRef.h"
#include "llvm/ConvertUTF.h"
#include "llvm/SmallString.h"
#include "llvm/SmallVector.h"
#include "llvm/StringRef.h"
#include "llvm/raw_ostream.h"
#include "support/SafeThread.h"
#include "support/atomic_static.h"
#include "support/deprecated.h"
#include "support/mutex.h"
namespace wpi {
namespace java {
// Gets a Java stack trace. 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).
std::string GetJavaStackTrace(
JNIEnv* env, std::string* func = nullptr,
llvm::StringRef excludeFuncPrefix = llvm::StringRef());
// Shim for backwards compatibility
template <const char* excludeFuncPrefix>
WPI_DEPRECATED("use StringRef function instead")
std::string GetJavaStackTrace(JNIEnv* env, std::string* func) {
return GetJavaStackTrace(
env, func,
excludeFuncPrefix == nullptr ? llvm::StringRef() : excludeFuncPrefix);
}
// 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;
return *this;
}
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 (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(
reinterpret_cast<void**>(&env), &args);
if (rs != JNI_OK) return;
std::unique_lock<wpi::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>)
};
inline std::string GetJavaStackTrace(JNIEnv* env, std::string* func,
llvm::StringRef excludeFuncPrefix) {
// 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.empty() &&
!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_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,26 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2015-2018 FIRST. 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;
uint64_t SizeUleb128(uint64_t val);
uint64_t WriteUleb128(llvm::SmallVectorImpl<char>& dest, uint64_t val);
uint64_t ReadUleb128(const char* addr, uint64_t* ret);
bool ReadUleb128(raw_istream& is, uint64_t* ret);
} // namespace wpi
#endif // WPIUTIL_SUPPORT_LEB128_H_

View File

@@ -0,0 +1,24 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017-2018 FIRST. 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. */
/*----------------------------------------------------------------------------*/
#pragma once
#include <mutex>
#include "priority_mutex.h"
namespace wpi {
#ifdef WPI_HAVE_PRIORITY_MUTEX
using mutex = priority_mutex;
using recursive_mutex = priority_recursive_mutex;
#else
using mutex = ::std::mutex;
using recursive_mutex = ::std::recursive_mutex;
#endif
} // namespace wpi

View File

@@ -0,0 +1,122 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 FIRST. 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. */
/*----------------------------------------------------------------------------*/
#pragma once
#ifdef __linux__
#include <pthread.h>
#endif
#include <condition_variable>
#include <memory>
#include <utility>
#include "priority_mutex.h"
namespace wpi {
#if defined(__linux__) && defined(WPI_HAVE_PRIORITY_MUTEX)
#define WPI_HAVE_PRIORITY_CONDITION_VARIABLE 1
class priority_condition_variable {
typedef std::chrono::system_clock clock;
public:
typedef pthread_cond_t* native_handle_type;
priority_condition_variable() noexcept = default;
~priority_condition_variable() noexcept { pthread_cond_destroy(&m_cond); }
priority_condition_variable(const priority_condition_variable&) = delete;
priority_condition_variable& operator=(const priority_condition_variable&) =
delete;
void notify_one() noexcept { pthread_cond_signal(&m_cond); }
void notify_all() noexcept { pthread_cond_broadcast(&m_cond); }
void wait(std::unique_lock<priority_mutex>& lock) noexcept {
int e = pthread_cond_wait(&m_cond, lock.mutex()->native_handle());
if (e) std::terminate();
}
template <typename Predicate>
void wait(std::unique_lock<priority_mutex>& lock, Predicate p) {
while (!p()) {
wait(lock);
}
}
template <typename Duration>
std::cv_status wait_until(
std::unique_lock<priority_mutex>& lock,
const std::chrono::time_point<clock, Duration>& atime) {
return wait_until_impl(lock, atime);
}
template <typename Clock, typename Duration>
std::cv_status wait_until(
std::unique_lock<priority_mutex>& lock,
const std::chrono::time_point<Clock, Duration>& atime) {
const typename Clock::time_point c_entry = Clock::now();
const clock::time_point s_entry = clock::now();
const auto delta = atime - c_entry;
const auto s_atime = s_entry + delta;
return wait_until_impl(lock, s_atime);
}
template <typename Clock, typename Duration, typename Predicate>
bool wait_until(std::unique_lock<priority_mutex>& lock,
const std::chrono::time_point<Clock, Duration>& atime,
Predicate p) {
while (!p()) {
if (wait_until(lock, atime) == std::cv_status::timeout) {
return p();
}
}
return true;
}
template <typename Rep, typename Period>
std::cv_status wait_for(std::unique_lock<priority_mutex>& lock,
const std::chrono::duration<Rep, Period>& rtime) {
return wait_until(lock, clock::now() + rtime);
}
template <typename Rep, typename Period, typename Predicate>
bool wait_for(std::unique_lock<priority_mutex>& lock,
const std::chrono::duration<Rep, Period>& rtime, Predicate p) {
return wait_until(lock, clock::now() + rtime, std::move(p));
}
native_handle_type native_handle() { return &m_cond; }
private:
pthread_cond_t m_cond = PTHREAD_COND_INITIALIZER;
template <typename Dur>
std::cv_status wait_until_impl(
std::unique_lock<priority_mutex>& lock,
const std::chrono::time_point<clock, Dur>& atime) {
auto s = std::chrono::time_point_cast<std::chrono::seconds>(atime);
auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(atime - s);
struct timespec ts = {
static_cast<std::time_t>(s.time_since_epoch().count()),
static_cast<long>(ns.count())}; // NOLINT(runtime/int)
pthread_cond_timedwait(&m_cond, lock.mutex()->native_handle(), &ts);
return (clock::now() < atime ? std::cv_status::no_timeout
: std::cv_status::timeout);
}
};
#endif
} // namespace wpi

View File

@@ -0,0 +1,84 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 FIRST. 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. */
/*----------------------------------------------------------------------------*/
#pragma once
// Allows usage with std::lock_guard without including <mutex> separately
#ifdef __linux__
#include <pthread.h>
#endif
#include <mutex>
namespace wpi {
#ifdef __linux__
#define WPI_HAVE_PRIORITY_MUTEX 1
class priority_recursive_mutex {
public:
typedef pthread_mutex_t* native_handle_type;
constexpr priority_recursive_mutex() noexcept = default;
priority_recursive_mutex(const priority_recursive_mutex&) = delete;
priority_recursive_mutex& operator=(const priority_recursive_mutex&) = delete;
// Lock the mutex, blocking until it's available.
void lock() { pthread_mutex_lock(&m_mutex); }
// Unlock the mutex.
void unlock() { pthread_mutex_unlock(&m_mutex); }
// Tries to lock the mutex.
bool try_lock() noexcept { return !pthread_mutex_trylock(&m_mutex); }
pthread_mutex_t* native_handle() { return &m_mutex; }
private:
// Do the equivalent of setting PTHREAD_PRIO_INHERIT and
// PTHREAD_MUTEX_RECURSIVE_NP.
#ifdef __PTHREAD_MUTEX_HAVE_PREV
pthread_mutex_t m_mutex = {
{0, 0, 0, 0, 0x20 | PTHREAD_MUTEX_RECURSIVE_NP, __PTHREAD_SPINS, {0, 0}}};
#else
pthread_mutex_t m_mutex = {
{0, 0, 0, 0x20 | PTHREAD_MUTEX_RECURSIVE_NP, 0, {__PTHREAD_SPINS}}};
#endif
};
class priority_mutex {
public:
typedef pthread_mutex_t* native_handle_type;
constexpr priority_mutex() noexcept = default;
priority_mutex(const priority_mutex&) = delete;
priority_mutex& operator=(const priority_mutex&) = delete;
// Lock the mutex, blocking until it's available.
void lock() { pthread_mutex_lock(&m_mutex); }
// Unlock the mutex.
void unlock() { pthread_mutex_unlock(&m_mutex); }
// Tries to lock the mutex.
bool try_lock() noexcept { return !pthread_mutex_trylock(&m_mutex); }
pthread_mutex_t* native_handle() { return &m_mutex; }
private:
// Do the equivalent of setting PTHREAD_PRIO_INHERIT.
#ifdef __PTHREAD_MUTEX_HAVE_PREV
pthread_mutex_t m_mutex = {{0, 0, 0, 0, 0x20, __PTHREAD_SPINS, {0, 0}}};
#else
pthread_mutex_t m_mutex = {{0, 0, 0, 0x20, 0, {__PTHREAD_SPINS}}};
#endif
};
#endif // __linux__
} // namespace wpi

View File

@@ -0,0 +1,115 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2015-2018 FIRST. 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>
#include <system_error>
#include "llvm/SmallVector.h"
#include "llvm/StringRef.h"
#include "llvm/Twine.h"
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, size_t len) {
read_impl(data, len);
return *this;
}
size_t readsome(void* data, size_t len) {
size_t readlen = std::min(in_avail(), len);
if (readlen == 0) return 0;
read_impl(data, readlen);
return readlen;
}
// Read a line from an input stream (up to a maximum length).
// The returned buffer will contain the trailing \n (unless the maximum length
// was reached). \r's are stripped from the buffer.
// @param buf Buffer for output
// @param maxLen Maximum length
// @return Line
llvm::StringRef getline(llvm::SmallVectorImpl<char>& buf, int maxLen);
virtual void close() = 0;
virtual 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, size_t len) = 0;
bool m_error = false;
};
class raw_mem_istream : public raw_istream {
public:
explicit raw_mem_istream(llvm::StringRef mem);
raw_mem_istream(const char* mem, size_t len) : m_cur(mem), m_left(len) {}
void close() override;
size_t in_avail() const override;
private:
void read_impl(void* data, size_t len) override;
const char* m_cur;
size_t m_left;
};
class raw_fd_istream : public raw_istream {
public:
raw_fd_istream(const llvm::Twine& filename, std::error_code& ec,
size_t bufSize = 4096);
raw_fd_istream(int fd, bool shouldClose, size_t bufSize = 4096);
~raw_fd_istream() override;
void close() override;
size_t in_avail() const override;
private:
void read_impl(void* data, size_t len) override;
char* m_buf;
char* m_cur;
char* m_end;
size_t m_bufSize;
int m_fd;
bool m_shouldClose;
};
} // namespace wpi
#endif // WPIUTIL_SUPPORT_RAW_ISTREAM_H_

View File

@@ -0,0 +1,34 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2015-2018 FIRST. 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;
size_t in_avail() const override;
private:
void read_impl(void* data, size_t len) override;
NetworkStream& m_stream;
int m_timeout;
};
} // namespace wpi
#endif // WPIUTIL_SUPPORT_RAW_SOCKET_ISTREAM_H_

View File

@@ -0,0 +1,42 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 FIRST. 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, 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_

View File

@@ -0,0 +1,56 @@
/*
sha1.hpp - header of
============
SHA-1 in C++
============
100% Public Domain.
Original C Code
-- Steve Reid <steve@edmweb.com>
Small changes to fit into bglibs
-- Bruce Guenter <bruce@untroubled.org>
Translation to simpler C++ Code
-- Volker Grabsch <vog@notjusthosting.com>
Safety fixes
-- Eugene Hopkinson <slowriot at voxelstorm dot com>
*/
#ifndef WPIUTIL_SUPPORT_SHA1_H_
#define WPIUTIL_SUPPORT_SHA1_H_
#include <stdint.h>
#include <string>
#include "llvm/StringRef.h"
namespace llvm {
template <typename T>
class SmallVectorImpl;
} // namespace llvm
namespace wpi {
class raw_istream;
class SHA1 {
public:
SHA1();
void Update(llvm::StringRef s);
void Update(raw_istream& is);
std::string Final();
llvm::StringRef Final(llvm::SmallVectorImpl<char>& buf);
static std::string FromFile(llvm::StringRef filename);
private:
uint32_t digest[5];
unsigned char buffer[64];
size_t buf_size;
uint64_t transforms;
};
} // namespace wpi
#endif // WPIUTIL_SUPPORT_SHA1_H_

View File

@@ -0,0 +1,71 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2015-2018 FIRST. 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_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* The default implementation used for Now().
* In general this is the time returned by the operating system.
* @return Time in microseconds.
*/
uint64_t WPI_NowDefault(void);
/**
* Set the implementation used by WPI_Now().
* The implementation must return monotonic time in microseconds to maintain
* the contract of WPI_Now().
* @param func Function called by WPI_Now() to return the time.
*/
void WPI_SetNowImpl(uint64_t (*func)(void));
/**
* Return a value representing the current time in microseconds.
* The epoch is not defined.
* @return Time in microseconds.
*/
uint64_t WPI_Now(void);
#ifdef __cplusplus
} // extern "C"
#endif
#ifdef __cplusplus
namespace wpi {
/**
* The default implementation used for Now().
* In general this is the time returned by the operating system.
* @return Time in microseconds.
*/
uint64_t NowDefault(void);
/**
* Set the implementation used by Now().
* The implementation must return monotonic time in microseconds to maintain
* the contract of Now().
* @param func Function called by Now() to return the time.
*/
void SetNowImpl(uint64_t (*func)());
/**
* Return a value representing the current time in microseconds.
* This is a monotonic clock with an undefined epoch.
* @return Time in microseconds.
*/
uint64_t Now(void);
} // namespace wpi
#endif
#endif // WPIUTIL_SUPPORT_TIMESTAMP_H_