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
259
src/main/native/include/llvm/AlignOf.h
Normal file
259
src/main/native/include/llvm/AlignOf.h
Normal file
@@ -0,0 +1,259 @@
|
||||
//===--- AlignOf.h - Portable calculation of type alignment -----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the AlignOf function that computes alignments for
|
||||
// arbitrary types.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_ALIGNOF_H
|
||||
#define LLVM_SUPPORT_ALIGNOF_H
|
||||
|
||||
#include "llvm/Compiler.h"
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
namespace detail {
|
||||
|
||||
// For everything other than an abstract class we can calulate alignment by
|
||||
// building a class with a single character and a member of the given type.
|
||||
template <typename T, bool = std::is_abstract<T>::value>
|
||||
struct AlignmentCalcImpl {
|
||||
char x;
|
||||
#if defined(_MSC_VER)
|
||||
// Disables "structure was padded due to __declspec(align())" warnings that are
|
||||
// generated by any class using AlignOf<T> with a manually specified alignment.
|
||||
// Although the warning is disabled in the LLVM project we need this pragma
|
||||
// as AlignOf.h is a published support header that's available for use
|
||||
// out-of-tree, and we would like that to compile cleanly at /W4.
|
||||
#pragma warning(suppress : 4324)
|
||||
#endif
|
||||
T t;
|
||||
private:
|
||||
AlignmentCalcImpl() = delete;
|
||||
};
|
||||
|
||||
// Abstract base class helper, this will have the minimal alignment and size
|
||||
// for any abstract class. We don't even define its destructor because this
|
||||
// type should never be used in a way that requires it.
|
||||
struct AlignmentCalcImplBase {
|
||||
virtual ~AlignmentCalcImplBase() = 0;
|
||||
};
|
||||
|
||||
// When we have an abstract class type, specialize the alignment computation
|
||||
// engine to create another abstract class that derives from both an empty
|
||||
// abstract base class and the provided type. This has the same effect as the
|
||||
// above except that it handles the fact that we can't actually create a member
|
||||
// of type T.
|
||||
template <typename T>
|
||||
struct AlignmentCalcImpl<T, true> : AlignmentCalcImplBase, T {
|
||||
~AlignmentCalcImpl() override = 0;
|
||||
};
|
||||
|
||||
} // End detail namespace.
|
||||
|
||||
/// AlignOf - A templated class that contains an enum value representing
|
||||
/// the alignment of the template argument. For example,
|
||||
/// AlignOf<int>::Alignment represents the alignment of type "int". The
|
||||
/// alignment calculated is the minimum alignment, and not necessarily
|
||||
/// the "desired" alignment returned by GCC's __alignof__ (for example). Note
|
||||
/// that because the alignment is an enum value, it can be used as a
|
||||
/// compile-time constant (e.g., for template instantiation).
|
||||
template <typename T>
|
||||
struct AlignOf {
|
||||
#ifndef _MSC_VER
|
||||
// Avoid warnings from GCC like:
|
||||
// comparison between 'enum llvm::AlignOf<X>::<anonymous>' and 'enum
|
||||
// llvm::AlignOf<Y>::<anonymous>' [-Wenum-compare]
|
||||
// by using constexpr instead of enum.
|
||||
// (except on MSVC, since it doesn't support constexpr yet).
|
||||
static constexpr unsigned Alignment = static_cast<unsigned int>(
|
||||
sizeof(detail::AlignmentCalcImpl<T>) - sizeof(T));
|
||||
#else
|
||||
enum {
|
||||
Alignment = static_cast<unsigned int>(
|
||||
sizeof(::llvm::detail::AlignmentCalcImpl<T>) - sizeof(T))
|
||||
};
|
||||
#endif
|
||||
enum { Alignment_GreaterEqual_2Bytes = Alignment >= 2 ? 1 : 0 };
|
||||
enum { Alignment_GreaterEqual_4Bytes = Alignment >= 4 ? 1 : 0 };
|
||||
enum { Alignment_GreaterEqual_8Bytes = Alignment >= 8 ? 1 : 0 };
|
||||
enum { Alignment_GreaterEqual_16Bytes = Alignment >= 16 ? 1 : 0 };
|
||||
|
||||
enum { Alignment_LessEqual_2Bytes = Alignment <= 2 ? 1 : 0 };
|
||||
enum { Alignment_LessEqual_4Bytes = Alignment <= 4 ? 1 : 0 };
|
||||
enum { Alignment_LessEqual_8Bytes = Alignment <= 8 ? 1 : 0 };
|
||||
enum { Alignment_LessEqual_16Bytes = Alignment <= 16 ? 1 : 0 };
|
||||
};
|
||||
|
||||
#ifndef _MSC_VER
|
||||
template <typename T> constexpr unsigned AlignOf<T>::Alignment;
|
||||
#endif
|
||||
|
||||
/// alignOf - A templated function that returns the minimum alignment of
|
||||
/// of a type. This provides no extra functionality beyond the AlignOf
|
||||
/// class besides some cosmetic cleanliness. Example usage:
|
||||
/// alignOf<int>() returns the alignment of an int.
|
||||
template <typename T>
|
||||
inline unsigned alignOf() { return AlignOf<T>::Alignment; }
|
||||
|
||||
/// \struct AlignedCharArray
|
||||
/// \brief Helper for building an aligned character array type.
|
||||
///
|
||||
/// This template is used to explicitly build up a collection of aligned
|
||||
/// character array types. We have to build these up using a macro and explicit
|
||||
/// specialization to cope with old versions of MSVC and GCC where only an
|
||||
/// integer literal can be used to specify an alignment constraint. Once built
|
||||
/// up here, we can then begin to indirect between these using normal C++
|
||||
/// template parameters.
|
||||
|
||||
// MSVC requires special handling here.
|
||||
#ifndef _MSC_VER
|
||||
|
||||
#if __has_feature(cxx_alignas)
|
||||
template<std::size_t Alignment, std::size_t Size>
|
||||
struct AlignedCharArray {
|
||||
alignas(Alignment) char buffer[Size];
|
||||
};
|
||||
|
||||
#elif defined(__GNUC__) || defined(__IBM_ATTRIBUTES)
|
||||
/// \brief Create a type with an aligned char buffer.
|
||||
template<std::size_t Alignment, std::size_t Size>
|
||||
struct AlignedCharArray;
|
||||
|
||||
#define LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(x) \
|
||||
template<std::size_t Size> \
|
||||
struct AlignedCharArray<x, Size> { \
|
||||
__attribute__((aligned(x))) char buffer[Size]; \
|
||||
};
|
||||
|
||||
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(1)
|
||||
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(2)
|
||||
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(4)
|
||||
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(8)
|
||||
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(16)
|
||||
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(32)
|
||||
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(64)
|
||||
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(128)
|
||||
|
||||
#undef LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT
|
||||
|
||||
#else
|
||||
# error No supported align as directive.
|
||||
#endif
|
||||
|
||||
#else // _MSC_VER
|
||||
|
||||
/// \brief Create a type with an aligned char buffer.
|
||||
template<std::size_t Alignment, std::size_t Size>
|
||||
struct AlignedCharArray;
|
||||
|
||||
// We provide special variations of this template for the most common
|
||||
// alignments because __declspec(align(...)) doesn't actually work when it is
|
||||
// a member of a by-value function argument in MSVC, even if the alignment
|
||||
// request is something reasonably like 8-byte or 16-byte. Note that we can't
|
||||
// even include the declspec with the union that forces the alignment because
|
||||
// MSVC warns on the existence of the declspec despite the union member forcing
|
||||
// proper alignment.
|
||||
|
||||
template<std::size_t Size>
|
||||
struct AlignedCharArray<1, Size> {
|
||||
union {
|
||||
char aligned;
|
||||
char buffer[Size];
|
||||
};
|
||||
};
|
||||
|
||||
template<std::size_t Size>
|
||||
struct AlignedCharArray<2, Size> {
|
||||
union {
|
||||
short aligned;
|
||||
char buffer[Size];
|
||||
};
|
||||
};
|
||||
|
||||
template<std::size_t Size>
|
||||
struct AlignedCharArray<4, Size> {
|
||||
union {
|
||||
int aligned;
|
||||
char buffer[Size];
|
||||
};
|
||||
};
|
||||
|
||||
template<std::size_t Size>
|
||||
struct AlignedCharArray<8, Size> {
|
||||
union {
|
||||
double aligned;
|
||||
char buffer[Size];
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// The rest of these are provided with a __declspec(align(...)) and we simply
|
||||
// can't pass them by-value as function arguments on MSVC.
|
||||
|
||||
#define LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(x) \
|
||||
template<std::size_t Size> \
|
||||
struct AlignedCharArray<x, Size> { \
|
||||
__declspec(align(x)) char buffer[Size]; \
|
||||
};
|
||||
|
||||
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(16)
|
||||
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(32)
|
||||
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(64)
|
||||
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(128)
|
||||
|
||||
#undef LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT
|
||||
|
||||
#endif // _MSC_VER
|
||||
|
||||
namespace detail {
|
||||
template <typename T1,
|
||||
typename T2 = char, typename T3 = char, typename T4 = char,
|
||||
typename T5 = char, typename T6 = char, typename T7 = char,
|
||||
typename T8 = char, typename T9 = char, typename T10 = char>
|
||||
class AlignerImpl {
|
||||
T1 t1; T2 t2; T3 t3; T4 t4; T5 t5; T6 t6; T7 t7; T8 t8; T9 t9; T10 t10;
|
||||
|
||||
AlignerImpl() = delete;
|
||||
};
|
||||
|
||||
template <typename T1,
|
||||
typename T2 = char, typename T3 = char, typename T4 = char,
|
||||
typename T5 = char, typename T6 = char, typename T7 = char,
|
||||
typename T8 = char, typename T9 = char, typename T10 = char>
|
||||
union SizerImpl {
|
||||
char arr1[sizeof(T1)], arr2[sizeof(T2)], arr3[sizeof(T3)], arr4[sizeof(T4)],
|
||||
arr5[sizeof(T5)], arr6[sizeof(T6)], arr7[sizeof(T7)], arr8[sizeof(T8)],
|
||||
arr9[sizeof(T9)], arr10[sizeof(T10)];
|
||||
};
|
||||
} // end namespace detail
|
||||
|
||||
/// \brief This union template exposes a suitably aligned and sized character
|
||||
/// array member which can hold elements of any of up to ten types.
|
||||
///
|
||||
/// These types may be arrays, structs, or any other types. The goal is to
|
||||
/// expose a char array buffer member which can be used as suitable storage for
|
||||
/// a placement new of any of these types. Support for more than ten types can
|
||||
/// be added at the cost of more boilerplate.
|
||||
template <typename T1,
|
||||
typename T2 = char, typename T3 = char, typename T4 = char,
|
||||
typename T5 = char, typename T6 = char, typename T7 = char,
|
||||
typename T8 = char, typename T9 = char, typename T10 = char>
|
||||
struct AlignedCharArrayUnion : llvm::AlignedCharArray<
|
||||
AlignOf<llvm::detail::AlignerImpl<T1, T2, T3, T4, T5,
|
||||
T6, T7, T8, T9, T10> >::Alignment,
|
||||
sizeof(::llvm::detail::SizerImpl<T1, T2, T3, T4, T5,
|
||||
T6, T7, T8, T9, T10>)> {
|
||||
};
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_SUPPORT_ALIGNOF_H
|
||||
397
src/main/native/include/llvm/ArrayRef.h
Normal file
397
src/main/native/include/llvm/ArrayRef.h
Normal file
@@ -0,0 +1,397 @@
|
||||
//===--- ArrayRef.h - Array Reference Wrapper -------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_ARRAYREF_H
|
||||
#define LLVM_ADT_ARRAYREF_H
|
||||
|
||||
#include "llvm/Compiler.h"
|
||||
#include "llvm/Hashing.h"
|
||||
#include "llvm/None.h"
|
||||
#include "llvm/SmallVector.h"
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
/// ArrayRef - Represent a constant reference to an array (0 or more elements
|
||||
/// consecutively in memory), i.e. a start pointer and a length. It allows
|
||||
/// various APIs to take consecutive elements easily and conveniently.
|
||||
///
|
||||
/// This class does not own the underlying data, it is expected to be used in
|
||||
/// situations where the data resides in some other buffer, whose lifetime
|
||||
/// extends past that of the ArrayRef. For this reason, it is not in general
|
||||
/// safe to store an ArrayRef.
|
||||
///
|
||||
/// This is intended to be trivially copyable, so it should be passed by
|
||||
/// value.
|
||||
template<typename T>
|
||||
class ArrayRef {
|
||||
public:
|
||||
typedef const T *iterator;
|
||||
typedef const T *const_iterator;
|
||||
typedef size_t size_type;
|
||||
|
||||
typedef std::reverse_iterator<iterator> reverse_iterator;
|
||||
|
||||
private:
|
||||
/// The start of the array, in an external buffer.
|
||||
const T *Data;
|
||||
|
||||
/// The number of elements.
|
||||
size_type Length;
|
||||
|
||||
public:
|
||||
/// @name Constructors
|
||||
/// @{
|
||||
|
||||
/// Construct an empty ArrayRef.
|
||||
/*implicit*/ ArrayRef() : Data(nullptr), Length(0) {}
|
||||
|
||||
/// Construct an empty ArrayRef from None.
|
||||
/*implicit*/ ArrayRef(NoneType) : Data(nullptr), Length(0) {}
|
||||
|
||||
/// Construct an ArrayRef from a single element.
|
||||
/*implicit*/ ArrayRef(const T &OneElt)
|
||||
: Data(&OneElt), Length(1) {}
|
||||
|
||||
/// Construct an ArrayRef from a pointer and length.
|
||||
/*implicit*/ ArrayRef(const T *data, size_t length)
|
||||
: Data(data), Length(length) {}
|
||||
|
||||
/// Construct an ArrayRef from a range.
|
||||
ArrayRef(const T *begin, const T *end)
|
||||
: Data(begin), Length(end - begin) {}
|
||||
|
||||
/// Construct an ArrayRef from a SmallVector. This is templated in order to
|
||||
/// avoid instantiating SmallVectorTemplateCommon<T> whenever we
|
||||
/// copy-construct an ArrayRef.
|
||||
template<typename U>
|
||||
/*implicit*/ ArrayRef(const SmallVectorTemplateCommon<T, U> &Vec)
|
||||
: Data(Vec.data()), Length(Vec.size()) {
|
||||
}
|
||||
|
||||
/// Construct an ArrayRef from a std::vector.
|
||||
template<typename A>
|
||||
/*implicit*/ ArrayRef(const std::vector<T, A> &Vec)
|
||||
: Data(Vec.data()), Length(Vec.size()) {}
|
||||
|
||||
/// Construct an ArrayRef from a C array.
|
||||
template <size_t N>
|
||||
/*implicit*/ LLVM_CONSTEXPR ArrayRef(const T (&Arr)[N])
|
||||
: Data(Arr), Length(N) {}
|
||||
|
||||
/// Construct an ArrayRef from a std::initializer_list.
|
||||
/*implicit*/ ArrayRef(const std::initializer_list<T> &Vec)
|
||||
: Data(Vec.begin() == Vec.end() ? (T*)nullptr : Vec.begin()),
|
||||
Length(Vec.size()) {}
|
||||
|
||||
/// Construct an ArrayRef<const T*> from ArrayRef<T*>. This uses SFINAE to
|
||||
/// ensure that only ArrayRefs of pointers can be converted.
|
||||
template <typename U>
|
||||
ArrayRef(
|
||||
const ArrayRef<U *> &A,
|
||||
typename std::enable_if<
|
||||
std::is_convertible<U *const *, T const *>::value>::type * = nullptr)
|
||||
: Data(A.data()), Length(A.size()) {}
|
||||
|
||||
/// Construct an ArrayRef<const T*> from a SmallVector<T*>. This is
|
||||
/// templated in order to avoid instantiating SmallVectorTemplateCommon<T>
|
||||
/// whenever we copy-construct an ArrayRef.
|
||||
template<typename U, typename DummyT>
|
||||
/*implicit*/ ArrayRef(
|
||||
const SmallVectorTemplateCommon<U *, DummyT> &Vec,
|
||||
typename std::enable_if<
|
||||
std::is_convertible<U *const *, T const *>::value>::type * = nullptr)
|
||||
: Data(Vec.data()), Length(Vec.size()) {
|
||||
}
|
||||
|
||||
/// Construct an ArrayRef<const T*> from std::vector<T*>. This uses SFINAE
|
||||
/// to ensure that only vectors of pointers can be converted.
|
||||
template<typename U, typename A>
|
||||
ArrayRef(const std::vector<U *, A> &Vec,
|
||||
typename std::enable_if<
|
||||
std::is_convertible<U *const *, T const *>::value>::type* = 0)
|
||||
: Data(Vec.data()), Length(Vec.size()) {}
|
||||
|
||||
/// @}
|
||||
/// @name Simple Operations
|
||||
/// @{
|
||||
|
||||
iterator begin() const { return Data; }
|
||||
iterator end() const { return Data + Length; }
|
||||
|
||||
reverse_iterator rbegin() const { return reverse_iterator(end()); }
|
||||
reverse_iterator rend() const { return reverse_iterator(begin()); }
|
||||
|
||||
/// empty - Check if the array is empty.
|
||||
bool empty() const { return Length == 0; }
|
||||
|
||||
const T *data() const { return Data; }
|
||||
|
||||
/// size - Get the array size.
|
||||
size_t size() const { return Length; }
|
||||
|
||||
/// front - Get the first element.
|
||||
const T &front() const {
|
||||
assert(!empty());
|
||||
return Data[0];
|
||||
}
|
||||
|
||||
/// back - Get the last element.
|
||||
const T &back() const {
|
||||
assert(!empty());
|
||||
return Data[Length-1];
|
||||
}
|
||||
|
||||
// copy - Allocate copy in Allocator and return ArrayRef<T> to it.
|
||||
template <typename Allocator> ArrayRef<T> copy(Allocator &A) {
|
||||
T *Buff = A.template Allocate<T>(Length);
|
||||
std::uninitialized_copy(begin(), end(), Buff);
|
||||
return ArrayRef<T>(Buff, Length);
|
||||
}
|
||||
|
||||
/// equals - Check for element-wise equality.
|
||||
bool equals(ArrayRef RHS) const {
|
||||
if (Length != RHS.Length)
|
||||
return false;
|
||||
return std::equal(begin(), end(), RHS.begin());
|
||||
}
|
||||
|
||||
/// slice(n) - Chop off the first N elements of the array.
|
||||
ArrayRef<T> slice(size_t N) const {
|
||||
assert(N <= size() && "Invalid specifier");
|
||||
return ArrayRef<T>(data()+N, size()-N);
|
||||
}
|
||||
|
||||
/// slice(n, m) - Chop off the first N elements of the array, and keep M
|
||||
/// elements in the array.
|
||||
ArrayRef<T> slice(size_t N, size_t M) const {
|
||||
assert(N+M <= size() && "Invalid specifier");
|
||||
return ArrayRef<T>(data()+N, M);
|
||||
}
|
||||
|
||||
/// \brief Drop the first \p N elements of the array.
|
||||
ArrayRef<T> drop_front(size_t N = 1) const {
|
||||
assert(size() >= N && "Dropping more elements than exist");
|
||||
return slice(N, size() - N);
|
||||
}
|
||||
|
||||
/// \brief Drop the last \p N elements of the array.
|
||||
ArrayRef<T> drop_back(size_t N = 1) const {
|
||||
assert(size() >= N && "Dropping more elements than exist");
|
||||
return slice(0, size() - N);
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Operator Overloads
|
||||
/// @{
|
||||
const T &operator[](size_t Index) const {
|
||||
assert(Index < Length && "Invalid index!");
|
||||
return Data[Index];
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Expensive Operations
|
||||
/// @{
|
||||
std::vector<T> vec() const {
|
||||
return std::vector<T>(Data, Data+Length);
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Conversion operators
|
||||
/// @{
|
||||
operator std::vector<T>() const {
|
||||
return std::vector<T>(Data, Data+Length);
|
||||
}
|
||||
|
||||
/// @}
|
||||
};
|
||||
|
||||
/// MutableArrayRef - Represent a mutable reference to an array (0 or more
|
||||
/// elements consecutively in memory), i.e. a start pointer and a length. It
|
||||
/// allows various APIs to take and modify consecutive elements easily and
|
||||
/// conveniently.
|
||||
///
|
||||
/// This class does not own the underlying data, it is expected to be used in
|
||||
/// situations where the data resides in some other buffer, whose lifetime
|
||||
/// extends past that of the MutableArrayRef. For this reason, it is not in
|
||||
/// general safe to store a MutableArrayRef.
|
||||
///
|
||||
/// This is intended to be trivially copyable, so it should be passed by
|
||||
/// value.
|
||||
template<typename T>
|
||||
class MutableArrayRef : public ArrayRef<T> {
|
||||
public:
|
||||
typedef T *iterator;
|
||||
|
||||
typedef std::reverse_iterator<iterator> reverse_iterator;
|
||||
|
||||
/// Construct an empty MutableArrayRef.
|
||||
/*implicit*/ MutableArrayRef() : ArrayRef<T>() {}
|
||||
|
||||
/// Construct an empty MutableArrayRef from None.
|
||||
/*implicit*/ MutableArrayRef(NoneType) : ArrayRef<T>() {}
|
||||
|
||||
/// Construct an MutableArrayRef from a single element.
|
||||
/*implicit*/ MutableArrayRef(T &OneElt) : ArrayRef<T>(OneElt) {}
|
||||
|
||||
/// Construct an MutableArrayRef from a pointer and length.
|
||||
/*implicit*/ MutableArrayRef(T *data, size_t length)
|
||||
: ArrayRef<T>(data, length) {}
|
||||
|
||||
/// Construct an MutableArrayRef from a range.
|
||||
MutableArrayRef(T *begin, T *end) : ArrayRef<T>(begin, end) {}
|
||||
|
||||
/// Construct an MutableArrayRef from a SmallVector.
|
||||
/*implicit*/ MutableArrayRef(SmallVectorImpl<T> &Vec)
|
||||
: ArrayRef<T>(Vec) {}
|
||||
|
||||
/// Construct a MutableArrayRef from a std::vector.
|
||||
/*implicit*/ MutableArrayRef(std::vector<T> &Vec)
|
||||
: ArrayRef<T>(Vec) {}
|
||||
|
||||
/// Construct an MutableArrayRef from a C array.
|
||||
template <size_t N>
|
||||
/*implicit*/ LLVM_CONSTEXPR MutableArrayRef(T (&Arr)[N])
|
||||
: ArrayRef<T>(Arr) {}
|
||||
|
||||
T *data() const { return const_cast<T*>(ArrayRef<T>::data()); }
|
||||
|
||||
iterator begin() const { return data(); }
|
||||
iterator end() const { return data() + this->size(); }
|
||||
|
||||
reverse_iterator rbegin() const { return reverse_iterator(end()); }
|
||||
reverse_iterator rend() const { return reverse_iterator(begin()); }
|
||||
|
||||
/// front - Get the first element.
|
||||
T &front() const {
|
||||
assert(!this->empty());
|
||||
return data()[0];
|
||||
}
|
||||
|
||||
/// back - Get the last element.
|
||||
T &back() const {
|
||||
assert(!this->empty());
|
||||
return data()[this->size()-1];
|
||||
}
|
||||
|
||||
/// slice(n) - Chop off the first N elements of the array.
|
||||
MutableArrayRef<T> slice(size_t N) const {
|
||||
assert(N <= this->size() && "Invalid specifier");
|
||||
return MutableArrayRef<T>(data()+N, this->size()-N);
|
||||
}
|
||||
|
||||
/// slice(n, m) - Chop off the first N elements of the array, and keep M
|
||||
/// elements in the array.
|
||||
MutableArrayRef<T> slice(size_t N, size_t M) const {
|
||||
assert(N+M <= this->size() && "Invalid specifier");
|
||||
return MutableArrayRef<T>(data()+N, M);
|
||||
}
|
||||
|
||||
/// \brief Drop the first \p N elements of the array.
|
||||
MutableArrayRef<T> drop_front(size_t N = 1) const {
|
||||
assert(this->size() >= N && "Dropping more elements than exist");
|
||||
return slice(N, this->size() - N);
|
||||
}
|
||||
|
||||
MutableArrayRef<T> drop_back(size_t N = 1) const {
|
||||
assert(this->size() >= N && "Dropping more elements than exist");
|
||||
return slice(0, this->size() - N);
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Operator Overloads
|
||||
/// @{
|
||||
T &operator[](size_t Index) const {
|
||||
assert(Index < this->size() && "Invalid index!");
|
||||
return data()[Index];
|
||||
}
|
||||
};
|
||||
|
||||
/// @name ArrayRef Convenience constructors
|
||||
/// @{
|
||||
|
||||
/// Construct an ArrayRef from a single element.
|
||||
template<typename T>
|
||||
ArrayRef<T> makeArrayRef(const T &OneElt) {
|
||||
return OneElt;
|
||||
}
|
||||
|
||||
/// Construct an ArrayRef from a pointer and length.
|
||||
template<typename T>
|
||||
ArrayRef<T> makeArrayRef(const T *data, size_t length) {
|
||||
return ArrayRef<T>(data, length);
|
||||
}
|
||||
|
||||
/// Construct an ArrayRef from a range.
|
||||
template<typename T>
|
||||
ArrayRef<T> makeArrayRef(const T *begin, const T *end) {
|
||||
return ArrayRef<T>(begin, end);
|
||||
}
|
||||
|
||||
/// Construct an ArrayRef from a SmallVector.
|
||||
template <typename T>
|
||||
ArrayRef<T> makeArrayRef(const SmallVectorImpl<T> &Vec) {
|
||||
return Vec;
|
||||
}
|
||||
|
||||
/// Construct an ArrayRef from a SmallVector.
|
||||
template <typename T, unsigned N>
|
||||
ArrayRef<T> makeArrayRef(const SmallVector<T, N> &Vec) {
|
||||
return Vec;
|
||||
}
|
||||
|
||||
/// Construct an ArrayRef from a std::vector.
|
||||
template<typename T>
|
||||
ArrayRef<T> makeArrayRef(const std::vector<T> &Vec) {
|
||||
return Vec;
|
||||
}
|
||||
|
||||
/// Construct an ArrayRef from an ArrayRef (no-op) (const)
|
||||
template <typename T> ArrayRef<T> makeArrayRef(const ArrayRef<T> &Vec) {
|
||||
return Vec;
|
||||
}
|
||||
|
||||
/// Construct an ArrayRef from an ArrayRef (no-op)
|
||||
template <typename T> ArrayRef<T> &makeArrayRef(ArrayRef<T> &Vec) {
|
||||
return Vec;
|
||||
}
|
||||
|
||||
/// Construct an ArrayRef from a C array.
|
||||
template<typename T, size_t N>
|
||||
ArrayRef<T> makeArrayRef(const T (&Arr)[N]) {
|
||||
return ArrayRef<T>(Arr);
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name ArrayRef Comparison Operators
|
||||
/// @{
|
||||
|
||||
template<typename T>
|
||||
inline bool operator==(ArrayRef<T> LHS, ArrayRef<T> RHS) {
|
||||
return LHS.equals(RHS);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool operator!=(ArrayRef<T> LHS, ArrayRef<T> RHS) {
|
||||
return !(LHS == RHS);
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
// ArrayRefs can be treated like a POD type.
|
||||
template <typename T> struct isPodLike;
|
||||
template <typename T> struct isPodLike<ArrayRef<T> > {
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
template <typename T> hash_code hash_value(ArrayRef<T> S) {
|
||||
return hash_combine_range(S.begin(), S.end());
|
||||
}
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_ADT_ARRAYREF_H
|
||||
92
src/main/native/include/llvm/Compiler.h
Normal file
92
src/main/native/include/llvm/Compiler.h
Normal file
@@ -0,0 +1,92 @@
|
||||
//===-- llvm/Support/Compiler.h - Compiler abstraction support --*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines several macros, based on the current compiler. This allows
|
||||
// use of compiler-specific features in a way that remains portable.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_COMPILER_H
|
||||
#define LLVM_SUPPORT_COMPILER_H
|
||||
|
||||
#ifndef __has_feature
|
||||
# define __has_feature(x) 0
|
||||
#endif
|
||||
|
||||
#ifndef __has_extension
|
||||
# define __has_extension(x) 0
|
||||
#endif
|
||||
|
||||
#ifndef __has_attribute
|
||||
# define __has_attribute(x) 0
|
||||
#endif
|
||||
|
||||
#ifndef __has_builtin
|
||||
# define __has_builtin(x) 0
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_GNUC_PREREQ
|
||||
/// \brief Extend the default __GNUC_PREREQ even if glibc's features.h isn't
|
||||
/// available.
|
||||
#ifndef LLVM_GNUC_PREREQ
|
||||
# if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
|
||||
# define LLVM_GNUC_PREREQ(maj, min, patch) \
|
||||
((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >= \
|
||||
((maj) << 20) + ((min) << 10) + (patch))
|
||||
# elif defined(__GNUC__) && defined(__GNUC_MINOR__)
|
||||
# define LLVM_GNUC_PREREQ(maj, min, patch) \
|
||||
((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10))
|
||||
# else
|
||||
# define LLVM_GNUC_PREREQ(maj, min, patch) 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef LLVM_CONSTEXPR
|
||||
# ifdef _MSC_VER
|
||||
# if _MSC_VER >= 1900
|
||||
# define LLVM_CONSTEXPR constexpr
|
||||
# else
|
||||
# define LLVM_CONSTEXPR
|
||||
# endif
|
||||
# elif defined(__has_feature)
|
||||
# if __has_feature(cxx_constexpr)
|
||||
# define LLVM_CONSTEXPR constexpr
|
||||
# else
|
||||
# define LLVM_CONSTEXPR
|
||||
# endif
|
||||
# elif defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
# define LLVM_CONSTEXPR constexpr
|
||||
# elif defined(__has_constexpr)
|
||||
# define LLVM_CONSTEXPR constexpr
|
||||
# else
|
||||
# define LLVM_CONSTEXPR
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef LLVM_ATTRIBUTE_UNUSED_RESULT
|
||||
#if __has_attribute(warn_unused_result) || LLVM_GNUC_PREREQ(3, 4, 0)
|
||||
#define LLVM_ATTRIBUTE_UNUSED_RESULT __attribute__((__warn_unused_result__))
|
||||
#elif defined(_MSC_VER)
|
||||
#define LLVM_ATTRIBUTE_UNUSED_RESULT _Check_return_
|
||||
#else
|
||||
#define LLVM_ATTRIBUTE_UNUSED_RESULT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef LLVM_UNLIKELY
|
||||
#if __has_builtin(__builtin_expect) || LLVM_GNUC_PREREQ(4, 0, 0)
|
||||
#define LLVM_LIKELY(EXPR) __builtin_expect((bool)(EXPR), true)
|
||||
#define LLVM_UNLIKELY(EXPR) __builtin_expect((bool)(EXPR), false)
|
||||
#else
|
||||
#define LLVM_LIKELY(EXPR) (EXPR)
|
||||
#define LLVM_UNLIKELY(EXPR) (EXPR)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
255
src/main/native/include/llvm/ConvertUTF.h
Normal file
255
src/main/native/include/llvm/ConvertUTF.h
Normal file
@@ -0,0 +1,255 @@
|
||||
/*===--- ConvertUTF.h - Universal Character Names conversions ---------------===
|
||||
*
|
||||
* The LLVM Compiler Infrastructure
|
||||
*
|
||||
* This file is distributed under the University of Illinois Open Source
|
||||
* License. See LICENSE.TXT for details.
|
||||
*
|
||||
*==------------------------------------------------------------------------==*/
|
||||
/*
|
||||
* Copyright 2001-2004 Unicode, Inc.
|
||||
*
|
||||
* Disclaimer
|
||||
*
|
||||
* This source code is provided as is by Unicode, Inc. No claims are
|
||||
* made as to fitness for any particular purpose. No warranties of any
|
||||
* kind are expressed or implied. The recipient agrees to determine
|
||||
* applicability of information provided. If this file has been
|
||||
* purchased on magnetic or optical media from Unicode, Inc., the
|
||||
* sole remedy for any claim will be exchange of defective media
|
||||
* within 90 days of receipt.
|
||||
*
|
||||
* Limitations on Rights to Redistribute This Code
|
||||
*
|
||||
* Unicode, Inc. hereby grants the right to freely use the information
|
||||
* supplied in this file in the creation of products supporting the
|
||||
* Unicode Standard, and to make copies of this file in any form
|
||||
* for internal or external distribution as long as this notice
|
||||
* remains attached.
|
||||
*/
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
|
||||
Conversions between UTF32, UTF-16, and UTF-8. Header file.
|
||||
|
||||
Several funtions are included here, forming a complete set of
|
||||
conversions between the three formats. UTF-7 is not included
|
||||
here, but is handled in a separate source file.
|
||||
|
||||
Each of these routines takes pointers to input buffers and output
|
||||
buffers. The input buffers are const.
|
||||
|
||||
Each routine converts the text between *sourceStart and sourceEnd,
|
||||
putting the result into the buffer between *targetStart and
|
||||
targetEnd. Note: the end pointers are *after* the last item: e.g.
|
||||
*(sourceEnd - 1) is the last item.
|
||||
|
||||
The return result indicates whether the conversion was successful,
|
||||
and if not, whether the problem was in the source or target buffers.
|
||||
(Only the first encountered problem is indicated.)
|
||||
|
||||
After the conversion, *sourceStart and *targetStart are both
|
||||
updated to point to the end of last text successfully converted in
|
||||
the respective buffers.
|
||||
|
||||
Input parameters:
|
||||
sourceStart - pointer to a pointer to the source buffer.
|
||||
The contents of this are modified on return so that
|
||||
it points at the next thing to be converted.
|
||||
targetStart - similarly, pointer to pointer to the target buffer.
|
||||
sourceEnd, targetEnd - respectively pointers to the ends of the
|
||||
two buffers, for overflow checking only.
|
||||
|
||||
These conversion functions take a ConversionFlags argument. When this
|
||||
flag is set to strict, both irregular sequences and isolated surrogates
|
||||
will cause an error. When the flag is set to lenient, both irregular
|
||||
sequences and isolated surrogates are converted.
|
||||
|
||||
Whether the flag is strict or lenient, all illegal sequences will cause
|
||||
an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>,
|
||||
or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code
|
||||
must check for illegal sequences.
|
||||
|
||||
When the flag is set to lenient, characters over 0x10FFFF are converted
|
||||
to the replacement character; otherwise (when the flag is set to strict)
|
||||
they constitute an error.
|
||||
|
||||
Output parameters:
|
||||
The value "sourceIllegal" is returned from some routines if the input
|
||||
sequence is malformed. When "sourceIllegal" is returned, the source
|
||||
value will point to the illegal value that caused the problem. E.g.,
|
||||
in UTF-8 when a sequence is malformed, it points to the start of the
|
||||
malformed sequence.
|
||||
|
||||
Author: Mark E. Davis, 1994.
|
||||
Rev History: Rick McGowan, fixes & updates May 2001.
|
||||
Fixes & updates, Sept 2001.
|
||||
|
||||
------------------------------------------------------------------------ */
|
||||
|
||||
#ifndef LLVM_SUPPORT_CONVERTUTF_H
|
||||
#define LLVM_SUPPORT_CONVERTUTF_H
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
The following 4 definitions are compiler-specific.
|
||||
The C standard does not guarantee that wchar_t has at least
|
||||
16 bits, so wchar_t is no less portable than unsigned short!
|
||||
All should be unsigned values to avoid sign extension during
|
||||
bit mask & shift operations.
|
||||
------------------------------------------------------------------------ */
|
||||
|
||||
typedef unsigned int UTF32; /* at least 32 bits */
|
||||
typedef unsigned short UTF16; /* at least 16 bits */
|
||||
typedef unsigned char UTF8; /* typically 8 bits */
|
||||
typedef bool Boolean; /* 0 or 1 */
|
||||
|
||||
/* Some fundamental constants */
|
||||
#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
|
||||
#define UNI_MAX_BMP (UTF32)0x0000FFFF
|
||||
#define UNI_MAX_UTF16 (UTF32)0x0010FFFF
|
||||
#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF
|
||||
#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF
|
||||
|
||||
#define UNI_MAX_UTF8_BYTES_PER_CODE_POINT 4
|
||||
|
||||
#define UNI_UTF16_BYTE_ORDER_MARK_NATIVE 0xFEFF
|
||||
#define UNI_UTF16_BYTE_ORDER_MARK_SWAPPED 0xFFFE
|
||||
|
||||
typedef enum {
|
||||
conversionOK, /* conversion successful */
|
||||
sourceExhausted, /* partial character in source, but hit end */
|
||||
targetExhausted, /* insuff. room in target for conversion */
|
||||
sourceIllegal /* source sequence is illegal/malformed */
|
||||
} ConversionResult;
|
||||
|
||||
typedef enum {
|
||||
strictConversion = 0,
|
||||
lenientConversion
|
||||
} ConversionFlags;
|
||||
|
||||
/* This is for C++ and does no harm in C */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
ConversionResult ConvertUTF8toUTF16 (
|
||||
const UTF8** sourceStart, const UTF8* sourceEnd,
|
||||
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
|
||||
|
||||
/**
|
||||
* Convert a partial UTF8 sequence to UTF32. If the sequence ends in an
|
||||
* incomplete code unit sequence, returns \c sourceExhausted.
|
||||
*/
|
||||
ConversionResult ConvertUTF8toUTF32Partial(
|
||||
const UTF8** sourceStart, const UTF8* sourceEnd,
|
||||
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
|
||||
|
||||
/**
|
||||
* Convert a partial UTF8 sequence to UTF32. If the sequence ends in an
|
||||
* incomplete code unit sequence, returns \c sourceIllegal.
|
||||
*/
|
||||
ConversionResult ConvertUTF8toUTF32(
|
||||
const UTF8** sourceStart, const UTF8* sourceEnd,
|
||||
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
|
||||
|
||||
ConversionResult ConvertUTF16toUTF8 (
|
||||
const UTF16** sourceStart, const UTF16* sourceEnd,
|
||||
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
|
||||
|
||||
ConversionResult ConvertUTF32toUTF8 (
|
||||
const UTF32** sourceStart, const UTF32* sourceEnd,
|
||||
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
|
||||
|
||||
ConversionResult ConvertUTF16toUTF32 (
|
||||
const UTF16** sourceStart, const UTF16* sourceEnd,
|
||||
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
|
||||
|
||||
ConversionResult ConvertUTF32toUTF16 (
|
||||
const UTF32** sourceStart, const UTF32* sourceEnd,
|
||||
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
|
||||
|
||||
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
|
||||
|
||||
Boolean isLegalUTF8String(const UTF8 **source, const UTF8 *sourceEnd);
|
||||
|
||||
unsigned getNumBytesForUTF8(UTF8 firstByte);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
/* Below are LLVM-specific wrappers of the functions above. */
|
||||
|
||||
#include "llvm/ArrayRef.h"
|
||||
#include "llvm/StringRef.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/**
|
||||
* Convert an Unicode code point to UTF8 sequence.
|
||||
*
|
||||
* \param Source a Unicode code point.
|
||||
* \param [in,out] ResultPtr pointer to the output buffer, needs to be at least
|
||||
* \c UNI_MAX_UTF8_BYTES_PER_CODE_POINT bytes. On success \c ResultPtr is
|
||||
* updated one past end of the converted sequence.
|
||||
*
|
||||
* \returns true on success.
|
||||
*/
|
||||
bool ConvertCodePointToUTF8(unsigned Source, char *&ResultPtr);
|
||||
|
||||
/**
|
||||
* Convert the first UTF8 sequence in the given source buffer to a UTF32
|
||||
* code point.
|
||||
*
|
||||
* \param [in,out] source A pointer to the source buffer. If the conversion
|
||||
* succeeds, this pointer will be updated to point to the byte just past the
|
||||
* end of the converted sequence.
|
||||
* \param sourceEnd A pointer just past the end of the source buffer.
|
||||
* \param [out] target The converted code
|
||||
* \param flags Whether the conversion is strict or lenient.
|
||||
*
|
||||
* \returns conversionOK on success
|
||||
*
|
||||
* \sa ConvertUTF8toUTF32
|
||||
*/
|
||||
static inline ConversionResult convertUTF8Sequence(const UTF8 **source,
|
||||
const UTF8 *sourceEnd,
|
||||
UTF32 *target,
|
||||
ConversionFlags flags) {
|
||||
if (*source == sourceEnd)
|
||||
return sourceExhausted;
|
||||
unsigned size = getNumBytesForUTF8(**source);
|
||||
if ((ptrdiff_t)size > sourceEnd - *source)
|
||||
return sourceExhausted;
|
||||
return ConvertUTF8toUTF32(source, *source + size, &target, target + 1, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a blob of text starts with a UTF-16 big or little endian byte
|
||||
* order mark.
|
||||
*/
|
||||
bool hasUTF16ByteOrderMark(ArrayRef<char> SrcBytes);
|
||||
|
||||
/**
|
||||
* Converts a UTF-16 string into a UTF-8 string.
|
||||
*
|
||||
* \returns true on success
|
||||
*/
|
||||
bool convertUTF16ToUTF8String(ArrayRef<UTF16> SrcUTF16,
|
||||
SmallVectorImpl<char> &DstUTF8);
|
||||
|
||||
/**
|
||||
* Converts a UTF-8 string into a UTF-16 string with native endianness.
|
||||
*
|
||||
* \returns true on success
|
||||
*/
|
||||
bool convertUTF8ToUTF16String(StringRef SrcUTF8,
|
||||
SmallVectorImpl<UTF16> &DstUTF16);
|
||||
|
||||
} /* end namespace llvm */
|
||||
|
||||
#endif
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
#endif
|
||||
1120
src/main/native/include/llvm/DenseMap.h
Normal file
1120
src/main/native/include/llvm/DenseMap.h
Normal file
File diff suppressed because it is too large
Load Diff
251
src/main/native/include/llvm/DenseMapInfo.h
Normal file
251
src/main/native/include/llvm/DenseMapInfo.h
Normal file
@@ -0,0 +1,251 @@
|
||||
//===- llvm/ADT/DenseMapInfo.h - Type traits for DenseMap -------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines DenseMapInfo traits for DenseMap.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_DENSEMAPINFO_H
|
||||
#define LLVM_ADT_DENSEMAPINFO_H
|
||||
|
||||
#include "llvm/ArrayRef.h"
|
||||
#include "llvm/Hashing.h"
|
||||
#include "llvm/StringRef.h"
|
||||
#include "llvm/PointerLikeTypeTraits.h"
|
||||
#include "llvm/type_traits.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
template<typename T>
|
||||
struct DenseMapInfo {
|
||||
//static inline T getEmptyKey();
|
||||
//static inline T getTombstoneKey();
|
||||
//static unsigned getHashValue(const T &Val);
|
||||
//static bool isEqual(const T &LHS, const T &RHS);
|
||||
};
|
||||
|
||||
template <typename T> struct CachedHash {
|
||||
CachedHash(T Val) : Val(std::move(Val)) {
|
||||
Hash = DenseMapInfo<T>::getHashValue(Val);
|
||||
}
|
||||
CachedHash(T Val, unsigned Hash) : Val(std::move(Val)), Hash(Hash) {}
|
||||
T Val;
|
||||
unsigned Hash;
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for all CachedHash<T>.
|
||||
template <typename T> struct DenseMapInfo<CachedHash<T>> {
|
||||
static CachedHash<T> getEmptyKey() {
|
||||
T N = DenseMapInfo<T>::getEmptyKey();
|
||||
return {N, 0};
|
||||
}
|
||||
static CachedHash<T> getTombstoneKey() {
|
||||
T N = DenseMapInfo<T>::getTombstoneKey();
|
||||
return {N, 0};
|
||||
}
|
||||
static unsigned getHashValue(CachedHash<T> Val) {
|
||||
assert(!isEqual(Val, getEmptyKey()) && "Cannot hash the empty key!");
|
||||
assert(!isEqual(Val, getTombstoneKey()) &&
|
||||
"Cannot hash the tombstone key!");
|
||||
return Val.Hash;
|
||||
}
|
||||
static bool isEqual(CachedHash<T> A, CachedHash<T> B) {
|
||||
return DenseMapInfo<T>::isEqual(A.Val, B.Val);
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for all pointers.
|
||||
template<typename T>
|
||||
struct DenseMapInfo<T*> {
|
||||
static inline T* getEmptyKey() {
|
||||
uintptr_t Val = static_cast<uintptr_t>(-1);
|
||||
Val <<= PointerLikeTypeTraits<T*>::NumLowBitsAvailable;
|
||||
return reinterpret_cast<T*>(Val);
|
||||
}
|
||||
static inline T* getTombstoneKey() {
|
||||
uintptr_t Val = static_cast<uintptr_t>(-2);
|
||||
Val <<= PointerLikeTypeTraits<T*>::NumLowBitsAvailable;
|
||||
return reinterpret_cast<T*>(Val);
|
||||
}
|
||||
static unsigned getHashValue(const T *PtrVal) {
|
||||
return (unsigned((uintptr_t)PtrVal) >> 4) ^
|
||||
(unsigned((uintptr_t)PtrVal) >> 9);
|
||||
}
|
||||
static bool isEqual(const T *LHS, const T *RHS) { return LHS == RHS; }
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for chars.
|
||||
template<> struct DenseMapInfo<char> {
|
||||
static inline char getEmptyKey() { return ~0; }
|
||||
static inline char getTombstoneKey() { return ~0 - 1; }
|
||||
static unsigned getHashValue(const char& Val) { return Val * 37U; }
|
||||
static bool isEqual(const char &LHS, const char &RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for unsigned ints.
|
||||
template<> struct DenseMapInfo<unsigned> {
|
||||
static inline unsigned getEmptyKey() { return ~0U; }
|
||||
static inline unsigned getTombstoneKey() { return ~0U - 1; }
|
||||
static unsigned getHashValue(const unsigned& Val) { return Val * 37U; }
|
||||
static bool isEqual(const unsigned& LHS, const unsigned& RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for unsigned longs.
|
||||
template<> struct DenseMapInfo<unsigned long> {
|
||||
static inline unsigned long getEmptyKey() { return ~0UL; }
|
||||
static inline unsigned long getTombstoneKey() { return ~0UL - 1L; }
|
||||
static unsigned getHashValue(const unsigned long& Val) {
|
||||
return (unsigned)(Val * 37UL);
|
||||
}
|
||||
static bool isEqual(const unsigned long& LHS, const unsigned long& RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for unsigned long longs.
|
||||
template<> struct DenseMapInfo<unsigned long long> {
|
||||
static inline unsigned long long getEmptyKey() { return ~0ULL; }
|
||||
static inline unsigned long long getTombstoneKey() { return ~0ULL - 1ULL; }
|
||||
static unsigned getHashValue(const unsigned long long& Val) {
|
||||
return (unsigned)(Val * 37ULL);
|
||||
}
|
||||
static bool isEqual(const unsigned long long& LHS,
|
||||
const unsigned long long& RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for ints.
|
||||
template<> struct DenseMapInfo<int> {
|
||||
static inline int getEmptyKey() { return 0x7fffffff; }
|
||||
static inline int getTombstoneKey() { return -0x7fffffff - 1; }
|
||||
static unsigned getHashValue(const int& Val) { return (unsigned)(Val * 37U); }
|
||||
static bool isEqual(const int& LHS, const int& RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for longs.
|
||||
template<> struct DenseMapInfo<long> {
|
||||
static inline long getEmptyKey() {
|
||||
return (1UL << (sizeof(long) * 8 - 1)) - 1UL;
|
||||
}
|
||||
static inline long getTombstoneKey() { return getEmptyKey() - 1L; }
|
||||
static unsigned getHashValue(const long& Val) {
|
||||
return (unsigned)(Val * 37UL);
|
||||
}
|
||||
static bool isEqual(const long& LHS, const long& RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for long longs.
|
||||
template<> struct DenseMapInfo<long long> {
|
||||
static inline long long getEmptyKey() { return 0x7fffffffffffffffLL; }
|
||||
static inline long long getTombstoneKey() { return -0x7fffffffffffffffLL-1; }
|
||||
static unsigned getHashValue(const long long& Val) {
|
||||
return (unsigned)(Val * 37ULL);
|
||||
}
|
||||
static bool isEqual(const long long& LHS,
|
||||
const long long& RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for all pairs whose members have info.
|
||||
template<typename T, typename U>
|
||||
struct DenseMapInfo<std::pair<T, U> > {
|
||||
typedef std::pair<T, U> Pair;
|
||||
typedef DenseMapInfo<T> FirstInfo;
|
||||
typedef DenseMapInfo<U> SecondInfo;
|
||||
|
||||
static inline Pair getEmptyKey() {
|
||||
return std::make_pair(FirstInfo::getEmptyKey(),
|
||||
SecondInfo::getEmptyKey());
|
||||
}
|
||||
static inline Pair getTombstoneKey() {
|
||||
return std::make_pair(FirstInfo::getTombstoneKey(),
|
||||
SecondInfo::getTombstoneKey());
|
||||
}
|
||||
static unsigned getHashValue(const Pair& PairVal) {
|
||||
uint64_t key = (uint64_t)FirstInfo::getHashValue(PairVal.first) << 32
|
||||
| (uint64_t)SecondInfo::getHashValue(PairVal.second);
|
||||
key += ~(key << 32);
|
||||
key ^= (key >> 22);
|
||||
key += ~(key << 13);
|
||||
key ^= (key >> 8);
|
||||
key += (key << 3);
|
||||
key ^= (key >> 15);
|
||||
key += ~(key << 27);
|
||||
key ^= (key >> 31);
|
||||
return (unsigned)key;
|
||||
}
|
||||
static bool isEqual(const Pair &LHS, const Pair &RHS) {
|
||||
return FirstInfo::isEqual(LHS.first, RHS.first) &&
|
||||
SecondInfo::isEqual(LHS.second, RHS.second);
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for StringRefs.
|
||||
template <> struct DenseMapInfo<StringRef> {
|
||||
static inline StringRef getEmptyKey() {
|
||||
return StringRef(reinterpret_cast<const char *>(~static_cast<uintptr_t>(0)),
|
||||
0);
|
||||
}
|
||||
static inline StringRef getTombstoneKey() {
|
||||
return StringRef(reinterpret_cast<const char *>(~static_cast<uintptr_t>(1)),
|
||||
0);
|
||||
}
|
||||
static unsigned getHashValue(StringRef Val) {
|
||||
assert(Val.data() != getEmptyKey().data() && "Cannot hash the empty key!");
|
||||
assert(Val.data() != getTombstoneKey().data() &&
|
||||
"Cannot hash the tombstone key!");
|
||||
return (unsigned)(hash_value(Val));
|
||||
}
|
||||
static bool isEqual(StringRef LHS, StringRef RHS) {
|
||||
if (RHS.data() == getEmptyKey().data())
|
||||
return LHS.data() == getEmptyKey().data();
|
||||
if (RHS.data() == getTombstoneKey().data())
|
||||
return LHS.data() == getTombstoneKey().data();
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for ArrayRefs.
|
||||
template <typename T> struct DenseMapInfo<ArrayRef<T>> {
|
||||
static inline ArrayRef<T> getEmptyKey() {
|
||||
return ArrayRef<T>(reinterpret_cast<const T *>(~static_cast<uintptr_t>(0)),
|
||||
size_t(0));
|
||||
}
|
||||
static inline ArrayRef<T> getTombstoneKey() {
|
||||
return ArrayRef<T>(reinterpret_cast<const T *>(~static_cast<uintptr_t>(1)),
|
||||
size_t(0));
|
||||
}
|
||||
static unsigned getHashValue(ArrayRef<T> Val) {
|
||||
assert(Val.data() != getEmptyKey().data() && "Cannot hash the empty key!");
|
||||
assert(Val.data() != getTombstoneKey().data() &&
|
||||
"Cannot hash the tombstone key!");
|
||||
return (unsigned)(hash_value(Val));
|
||||
}
|
||||
static bool isEqual(ArrayRef<T> LHS, ArrayRef<T> RHS) {
|
||||
if (RHS.data() == getEmptyKey().data())
|
||||
return LHS.data() == getEmptyKey().data();
|
||||
if (RHS.data() == getTombstoneKey().data())
|
||||
return LHS.data() == getTombstoneKey().data();
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
97
src/main/native/include/llvm/EpochTracker.h
Normal file
97
src/main/native/include/llvm/EpochTracker.h
Normal file
@@ -0,0 +1,97 @@
|
||||
//===- llvm/ADT/EpochTracker.h - ADT epoch tracking --------------*- C++ -*-==//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the DebugEpochBase and DebugEpochBase::HandleBase classes.
|
||||
// These can be used to write iterators that are fail-fast when LLVM is built
|
||||
// with asserts enabled.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_EPOCH_TRACKER_H
|
||||
#define LLVM_ADT_EPOCH_TRACKER_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
#ifdef NDEBUG //ifndef LLVM_ENABLE_ABI_BREAKING_CHECKS
|
||||
|
||||
class DebugEpochBase {
|
||||
public:
|
||||
void incrementEpoch() {}
|
||||
|
||||
class HandleBase {
|
||||
public:
|
||||
HandleBase() = default;
|
||||
explicit HandleBase(const DebugEpochBase *) {}
|
||||
bool isHandleInSync() const { return true; }
|
||||
const void *getEpochAddress() const { return nullptr; }
|
||||
};
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
/// \brief A base class for data structure classes wishing to make iterators
|
||||
/// ("handles") pointing into themselves fail-fast. When building without
|
||||
/// asserts, this class is empty and does nothing.
|
||||
///
|
||||
/// DebugEpochBase does not by itself track handles pointing into itself. The
|
||||
/// expectation is that routines touching the handles will poll on
|
||||
/// isHandleInSync at appropriate points to assert that the handle they're using
|
||||
/// is still valid.
|
||||
///
|
||||
class DebugEpochBase {
|
||||
uint64_t Epoch;
|
||||
|
||||
public:
|
||||
DebugEpochBase() : Epoch(0) {}
|
||||
|
||||
/// \brief Calling incrementEpoch invalidates all handles pointing into the
|
||||
/// calling instance.
|
||||
void incrementEpoch() { ++Epoch; }
|
||||
|
||||
/// \brief The destructor calls incrementEpoch to make use-after-free bugs
|
||||
/// more likely to crash deterministically.
|
||||
~DebugEpochBase() { incrementEpoch(); }
|
||||
|
||||
/// \brief A base class for iterator classes ("handles") that wish to poll for
|
||||
/// iterator invalidating modifications in the underlying data structure.
|
||||
/// When LLVM is built without asserts, this class is empty and does nothing.
|
||||
///
|
||||
/// HandleBase does not track the parent data structure by itself. It expects
|
||||
/// the routines modifying the data structure to call incrementEpoch when they
|
||||
/// make an iterator-invalidating modification.
|
||||
///
|
||||
class HandleBase {
|
||||
const uint64_t *EpochAddress;
|
||||
uint64_t EpochAtCreation;
|
||||
|
||||
public:
|
||||
HandleBase() : EpochAddress(nullptr), EpochAtCreation(UINT64_MAX) {}
|
||||
|
||||
explicit HandleBase(const DebugEpochBase *Parent)
|
||||
: EpochAddress(&Parent->Epoch), EpochAtCreation(Parent->Epoch) {}
|
||||
|
||||
/// \brief Returns true if the DebugEpochBase this Handle is linked to has
|
||||
/// not called incrementEpoch on itself since the creation of this
|
||||
/// HandleBase instance.
|
||||
bool isHandleInSync() const { return *EpochAddress == EpochAtCreation; }
|
||||
|
||||
/// \brief Returns a pointer to the epoch word stored in the data structure
|
||||
/// this handle points into. Can be used to check if two iterators point
|
||||
/// into the same data structure.
|
||||
const void *getEpochAddress() const { return EpochAddress; }
|
||||
};
|
||||
};
|
||||
|
||||
#endif // LLVM_ENABLE_ABI_BREAKING_CHECKS
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
202
src/main/native/include/llvm/Format.h
Normal file
202
src/main/native/include/llvm/Format.h
Normal file
@@ -0,0 +1,202 @@
|
||||
//===- Format.h - Efficient printf-style formatting for streams -*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the format() function, which can be used with other
|
||||
// LLVM subsystems to provide printf-style formatting. This gives all the power
|
||||
// and risk of printf. This can be used like this (with raw_ostreams as an
|
||||
// example):
|
||||
//
|
||||
// OS << "mynumber: " << format("%4.5f", 1234.412) << '\n';
|
||||
//
|
||||
// Or if you prefer:
|
||||
//
|
||||
// OS << format("mynumber: %4.5f\n", 1234.412);
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_FORMAT_H
|
||||
#define LLVM_SUPPORT_FORMAT_H
|
||||
|
||||
#include "llvm/STLExtras.h"
|
||||
#include "llvm/StringRef.h"
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <tuple>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// This is a helper class used for handling formatted output. It is the
|
||||
/// abstract base class of a templated derived class.
|
||||
class format_object_base {
|
||||
protected:
|
||||
const char *Fmt;
|
||||
~format_object_base() = default; // Disallow polymorphic deletion.
|
||||
format_object_base(const format_object_base &) = default;
|
||||
virtual void home(); // Out of line virtual method.
|
||||
|
||||
/// Call snprintf() for this object, on the given buffer and size.
|
||||
virtual int snprint(char *Buffer, unsigned BufferSize) const = 0;
|
||||
|
||||
public:
|
||||
format_object_base(const char *fmt) : Fmt(fmt) {}
|
||||
|
||||
/// Format the object into the specified buffer. On success, this returns
|
||||
/// the length of the formatted string. If the buffer is too small, this
|
||||
/// returns a length to retry with, which will be larger than BufferSize.
|
||||
unsigned print(char *Buffer, unsigned BufferSize) const {
|
||||
assert(BufferSize && "Invalid buffer size!");
|
||||
|
||||
// Print the string, leaving room for the terminating null.
|
||||
int N = snprint(Buffer, BufferSize);
|
||||
|
||||
// VC++ and old GlibC return negative on overflow, just double the size.
|
||||
if (N < 0)
|
||||
return BufferSize * 2;
|
||||
|
||||
// Other implementations yield number of bytes needed, not including the
|
||||
// final '\0'.
|
||||
if (unsigned(N) >= BufferSize)
|
||||
return N + 1;
|
||||
|
||||
// Otherwise N is the length of output (not including the final '\0').
|
||||
return N;
|
||||
}
|
||||
};
|
||||
|
||||
/// These are templated helper classes used by the format function that
|
||||
/// capture the object to be formated and the format string. When actually
|
||||
/// printed, this synthesizes the string into a temporary buffer provided and
|
||||
/// returns whether or not it is big enough.
|
||||
|
||||
template <typename... Ts>
|
||||
class format_object final : public format_object_base {
|
||||
std::tuple<Ts...> Vals;
|
||||
|
||||
template <std::size_t... Is>
|
||||
int snprint_tuple(char *Buffer, unsigned BufferSize,
|
||||
index_sequence<Is...>) const {
|
||||
#ifdef _MSC_VER
|
||||
return _snprintf(Buffer, BufferSize, Fmt, std::get<Is>(Vals)...);
|
||||
#else
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
|
||||
#endif
|
||||
return snprintf(Buffer, BufferSize, Fmt, std::get<Is>(Vals)...);
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
format_object(const char *fmt, const Ts &... vals)
|
||||
: format_object_base(fmt), Vals(vals...) {}
|
||||
|
||||
int snprint(char *Buffer, unsigned BufferSize) const override {
|
||||
return snprint_tuple(Buffer, BufferSize, index_sequence_for<Ts...>());
|
||||
}
|
||||
};
|
||||
|
||||
/// These are helper functions used to produce formatted output. They use
|
||||
/// template type deduction to construct the appropriate instance of the
|
||||
/// format_object class to simplify their construction.
|
||||
///
|
||||
/// This is typically used like:
|
||||
/// \code
|
||||
/// OS << format("%0.4f", myfloat) << '\n';
|
||||
/// \endcode
|
||||
|
||||
template <typename... Ts>
|
||||
inline format_object<Ts...> format(const char *Fmt, const Ts &... Vals) {
|
||||
return format_object<Ts...>(Fmt, Vals...);
|
||||
}
|
||||
|
||||
/// This is a helper class used for left_justify() and right_justify().
|
||||
class FormattedString {
|
||||
StringRef Str;
|
||||
unsigned Width;
|
||||
bool RightJustify;
|
||||
friend class raw_ostream;
|
||||
|
||||
public:
|
||||
FormattedString(StringRef S, unsigned W, bool R)
|
||||
: Str(S), Width(W), RightJustify(R) { }
|
||||
};
|
||||
|
||||
/// left_justify - append spaces after string so total output is
|
||||
/// \p Width characters. If \p Str is larger that \p Width, full string
|
||||
/// is written with no padding.
|
||||
inline FormattedString left_justify(StringRef Str, unsigned Width) {
|
||||
return FormattedString(Str, Width, false);
|
||||
}
|
||||
|
||||
/// right_justify - add spaces before string so total output is
|
||||
/// \p Width characters. If \p Str is larger that \p Width, full string
|
||||
/// is written with no padding.
|
||||
inline FormattedString right_justify(StringRef Str, unsigned Width) {
|
||||
return FormattedString(Str, Width, true);
|
||||
}
|
||||
|
||||
/// This is a helper class used for format_hex() and format_decimal().
|
||||
class FormattedNumber {
|
||||
uint64_t HexValue;
|
||||
int64_t DecValue;
|
||||
unsigned Width;
|
||||
bool Hex;
|
||||
bool Upper;
|
||||
bool HexPrefix;
|
||||
friend class raw_ostream;
|
||||
|
||||
public:
|
||||
FormattedNumber(uint64_t HV, int64_t DV, unsigned W, bool H, bool U,
|
||||
bool Prefix)
|
||||
: HexValue(HV), DecValue(DV), Width(W), Hex(H), Upper(U),
|
||||
HexPrefix(Prefix) {}
|
||||
};
|
||||
|
||||
/// format_hex - Output \p N as a fixed width hexadecimal. If number will not
|
||||
/// fit in width, full number is still printed. Examples:
|
||||
/// OS << format_hex(255, 4) => 0xff
|
||||
/// OS << format_hex(255, 4, true) => 0xFF
|
||||
/// OS << format_hex(255, 6) => 0x00ff
|
||||
/// OS << format_hex(255, 2) => 0xff
|
||||
inline FormattedNumber format_hex(uint64_t N, unsigned Width,
|
||||
bool Upper = false) {
|
||||
assert(Width <= 18 && "hex width must be <= 18");
|
||||
return FormattedNumber(N, 0, Width, true, Upper, true);
|
||||
}
|
||||
|
||||
/// format_hex_no_prefix - Output \p N as a fixed width hexadecimal. Does not
|
||||
/// prepend '0x' to the outputted string. If number will not fit in width,
|
||||
/// full number is still printed. Examples:
|
||||
/// OS << format_hex_no_prefix(255, 2) => ff
|
||||
/// OS << format_hex_no_prefix(255, 2, true) => FF
|
||||
/// OS << format_hex_no_prefix(255, 4) => 00ff
|
||||
/// OS << format_hex_no_prefix(255, 1) => ff
|
||||
inline FormattedNumber format_hex_no_prefix(uint64_t N, unsigned Width,
|
||||
bool Upper = false) {
|
||||
assert(Width <= 16 && "hex width must be <= 16");
|
||||
return FormattedNumber(N, 0, Width, true, Upper, false);
|
||||
}
|
||||
|
||||
/// format_decimal - Output \p N as a right justified, fixed-width decimal. If
|
||||
/// number will not fit in width, full number is still printed. Examples:
|
||||
/// OS << format_decimal(0, 5) => " 0"
|
||||
/// OS << format_decimal(255, 5) => " 255"
|
||||
/// OS << format_decimal(-1, 3) => " -1"
|
||||
/// OS << format_decimal(12345, 3) => "12345"
|
||||
inline FormattedNumber format_decimal(int64_t N, unsigned Width) {
|
||||
return FormattedNumber(0, N, Width, false, false, false);
|
||||
}
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
659
src/main/native/include/llvm/Hashing.h
Normal file
659
src/main/native/include/llvm/Hashing.h
Normal file
@@ -0,0 +1,659 @@
|
||||
//===-- llvm/ADT/Hashing.h - Utilities for hashing --------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the newly proposed standard C++ interfaces for hashing
|
||||
// arbitrary data and building hash functions for user-defined types. This
|
||||
// interface was originally proposed in N3333[1] and is currently under review
|
||||
// for inclusion in a future TR and/or standard.
|
||||
//
|
||||
// The primary interfaces provide are comprised of one type and three functions:
|
||||
//
|
||||
// -- 'hash_code' class is an opaque type representing the hash code for some
|
||||
// data. It is the intended product of hashing, and can be used to implement
|
||||
// hash tables, checksumming, and other common uses of hashes. It is not an
|
||||
// integer type (although it can be converted to one) because it is risky
|
||||
// to assume much about the internals of a hash_code. In particular, each
|
||||
// execution of the program has a high probability of producing a different
|
||||
// hash_code for a given input. Thus their values are not stable to save or
|
||||
// persist, and should only be used during the execution for the
|
||||
// construction of hashing datastructures.
|
||||
//
|
||||
// -- 'hash_value' is a function designed to be overloaded for each
|
||||
// user-defined type which wishes to be used within a hashing context. It
|
||||
// should be overloaded within the user-defined type's namespace and found
|
||||
// via ADL. Overloads for primitive types are provided by this library.
|
||||
//
|
||||
// -- 'hash_combine' and 'hash_combine_range' are functions designed to aid
|
||||
// programmers in easily and intuitively combining a set of data into
|
||||
// a single hash_code for their object. They should only logically be used
|
||||
// within the implementation of a 'hash_value' routine or similar context.
|
||||
//
|
||||
// Note that 'hash_combine_range' contains very special logic for hashing
|
||||
// a contiguous array of integers or pointers. This logic is *extremely* fast,
|
||||
// on a modern Intel "Gainestown" Xeon (Nehalem uarch) @2.2 GHz, these were
|
||||
// benchmarked at over 6.5 GiB/s for large keys, and <20 cycles/hash for keys
|
||||
// under 32-bytes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_HASHING_H
|
||||
#define LLVM_ADT_HASHING_H
|
||||
|
||||
#include "llvm/type_traits.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// \brief An opaque object representing a hash code.
|
||||
///
|
||||
/// This object represents the result of hashing some entity. It is intended to
|
||||
/// be used to implement hashtables or other hashing-based data structures.
|
||||
/// While it wraps and exposes a numeric value, this value should not be
|
||||
/// trusted to be stable or predictable across processes or executions.
|
||||
///
|
||||
/// In order to obtain the hash_code for an object 'x':
|
||||
/// \code
|
||||
/// using llvm::hash_value;
|
||||
/// llvm::hash_code code = hash_value(x);
|
||||
/// \endcode
|
||||
class hash_code {
|
||||
size_t value;
|
||||
|
||||
public:
|
||||
/// \brief Default construct a hash_code.
|
||||
/// Note that this leaves the value uninitialized.
|
||||
hash_code() = default;
|
||||
|
||||
/// \brief Form a hash code directly from a numerical value.
|
||||
hash_code(size_t value) : value(value) {}
|
||||
|
||||
/// \brief Convert the hash code to its numerical value for use.
|
||||
/*explicit*/ operator size_t() const { return value; }
|
||||
|
||||
friend bool operator==(const hash_code &lhs, const hash_code &rhs) {
|
||||
return lhs.value == rhs.value;
|
||||
}
|
||||
friend bool operator!=(const hash_code &lhs, const hash_code &rhs) {
|
||||
return lhs.value != rhs.value;
|
||||
}
|
||||
|
||||
/// \brief Allow a hash_code to be directly run through hash_value.
|
||||
friend size_t hash_value(const hash_code &code) { return code.value; }
|
||||
};
|
||||
|
||||
/// \brief Compute a hash_code for any integer value.
|
||||
///
|
||||
/// Note that this function is intended to compute the same hash_code for
|
||||
/// a particular value without regard to the pre-promotion type. This is in
|
||||
/// contrast to hash_combine which may produce different hash_codes for
|
||||
/// differing argument types even if they would implicit promote to a common
|
||||
/// type without changing the value.
|
||||
template <typename T>
|
||||
typename std::enable_if<is_integral_or_enum<T>::value, hash_code>::type
|
||||
hash_value(T value);
|
||||
|
||||
/// \brief Compute a hash_code for a pointer's address.
|
||||
///
|
||||
/// N.B.: This hashes the *address*. Not the value and not the type.
|
||||
template <typename T> hash_code hash_value(const T *ptr);
|
||||
|
||||
/// \brief Compute a hash_code for a pair of objects.
|
||||
template <typename T, typename U>
|
||||
hash_code hash_value(const std::pair<T, U> &arg);
|
||||
|
||||
/// \brief Compute a hash_code for a standard string.
|
||||
template <typename T>
|
||||
hash_code hash_value(const std::basic_string<T> &arg);
|
||||
|
||||
|
||||
/// \brief Override the execution seed with a fixed value.
|
||||
///
|
||||
/// This hashing library uses a per-execution seed designed to change on each
|
||||
/// run with high probability in order to ensure that the hash codes are not
|
||||
/// attackable and to ensure that output which is intended to be stable does
|
||||
/// not rely on the particulars of the hash codes produced.
|
||||
///
|
||||
/// That said, there are use cases where it is important to be able to
|
||||
/// reproduce *exactly* a specific behavior. To that end, we provide a function
|
||||
/// which will forcibly set the seed to a fixed value. This must be done at the
|
||||
/// start of the program, before any hashes are computed. Also, it cannot be
|
||||
/// undone. This makes it thread-hostile and very hard to use outside of
|
||||
/// immediately on start of a simple program designed for reproducible
|
||||
/// behavior.
|
||||
void set_fixed_execution_hash_seed(size_t fixed_value);
|
||||
|
||||
|
||||
// All of the implementation details of actually computing the various hash
|
||||
// code values are held within this namespace. These routines are included in
|
||||
// the header file mainly to allow inlining and constant propagation.
|
||||
namespace hashing {
|
||||
namespace detail {
|
||||
|
||||
inline uint64_t fetch64(const char *p) {
|
||||
uint64_t result;
|
||||
memcpy(&result, p, sizeof(result));
|
||||
//if (sys::IsBigEndianHost)
|
||||
// sys::swapByteOrder(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline uint32_t fetch32(const char *p) {
|
||||
uint32_t result;
|
||||
memcpy(&result, p, sizeof(result));
|
||||
//if (sys::IsBigEndianHost)
|
||||
// sys::swapByteOrder(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Some primes between 2^63 and 2^64 for various uses.
|
||||
static const uint64_t k0 = 0xc3a5c85c97cb3127ULL;
|
||||
static const uint64_t k1 = 0xb492b66fbe98f273ULL;
|
||||
static const uint64_t k2 = 0x9ae16a3b2f90404fULL;
|
||||
static const uint64_t k3 = 0xc949d7c7509e6557ULL;
|
||||
|
||||
/// \brief Bitwise right rotate.
|
||||
/// Normally this will compile to a single instruction, especially if the
|
||||
/// shift is a manifest constant.
|
||||
inline uint64_t rotate(uint64_t val, size_t shift) {
|
||||
// Avoid shifting by 64: doing so yields an undefined result.
|
||||
return shift == 0 ? val : ((val >> shift) | (val << (64 - shift)));
|
||||
}
|
||||
|
||||
inline uint64_t shift_mix(uint64_t val) {
|
||||
return val ^ (val >> 47);
|
||||
}
|
||||
|
||||
inline uint64_t hash_16_bytes(uint64_t low, uint64_t high) {
|
||||
// Murmur-inspired hashing.
|
||||
const uint64_t kMul = 0x9ddfea08eb382d69ULL;
|
||||
uint64_t a = (low ^ high) * kMul;
|
||||
a ^= (a >> 47);
|
||||
uint64_t b = (high ^ a) * kMul;
|
||||
b ^= (b >> 47);
|
||||
b *= kMul;
|
||||
return b;
|
||||
}
|
||||
|
||||
inline uint64_t hash_1to3_bytes(const char *s, size_t len, uint64_t seed) {
|
||||
uint8_t a = s[0];
|
||||
uint8_t b = s[len >> 1];
|
||||
uint8_t c = s[len - 1];
|
||||
uint32_t y = static_cast<uint32_t>(a) + (static_cast<uint32_t>(b) << 8);
|
||||
uint32_t z = len + (static_cast<uint32_t>(c) << 2);
|
||||
return shift_mix(y * k2 ^ z * k3 ^ seed) * k2;
|
||||
}
|
||||
|
||||
inline uint64_t hash_4to8_bytes(const char *s, size_t len, uint64_t seed) {
|
||||
uint64_t a = fetch32(s);
|
||||
return hash_16_bytes(len + (a << 3), seed ^ fetch32(s + len - 4));
|
||||
}
|
||||
|
||||
inline uint64_t hash_9to16_bytes(const char *s, size_t len, uint64_t seed) {
|
||||
uint64_t a = fetch64(s);
|
||||
uint64_t b = fetch64(s + len - 8);
|
||||
return hash_16_bytes(seed ^ a, rotate(b + len, len)) ^ b;
|
||||
}
|
||||
|
||||
inline uint64_t hash_17to32_bytes(const char *s, size_t len, uint64_t seed) {
|
||||
uint64_t a = fetch64(s) * k1;
|
||||
uint64_t b = fetch64(s + 8);
|
||||
uint64_t c = fetch64(s + len - 8) * k2;
|
||||
uint64_t d = fetch64(s + len - 16) * k0;
|
||||
return hash_16_bytes(rotate(a - b, 43) + rotate(c ^ seed, 30) + d,
|
||||
a + rotate(b ^ k3, 20) - c + len + seed);
|
||||
}
|
||||
|
||||
inline uint64_t hash_33to64_bytes(const char *s, size_t len, uint64_t seed) {
|
||||
uint64_t z = fetch64(s + 24);
|
||||
uint64_t a = fetch64(s) + (len + fetch64(s + len - 16)) * k0;
|
||||
uint64_t b = rotate(a + z, 52);
|
||||
uint64_t c = rotate(a, 37);
|
||||
a += fetch64(s + 8);
|
||||
c += rotate(a, 7);
|
||||
a += fetch64(s + 16);
|
||||
uint64_t vf = a + z;
|
||||
uint64_t vs = b + rotate(a, 31) + c;
|
||||
a = fetch64(s + 16) + fetch64(s + len - 32);
|
||||
z = fetch64(s + len - 8);
|
||||
b = rotate(a + z, 52);
|
||||
c = rotate(a, 37);
|
||||
a += fetch64(s + len - 24);
|
||||
c += rotate(a, 7);
|
||||
a += fetch64(s + len - 16);
|
||||
uint64_t wf = a + z;
|
||||
uint64_t ws = b + rotate(a, 31) + c;
|
||||
uint64_t r = shift_mix((vf + ws) * k2 + (wf + vs) * k0);
|
||||
return shift_mix((seed ^ (r * k0)) + vs) * k2;
|
||||
}
|
||||
|
||||
inline uint64_t hash_short(const char *s, size_t length, uint64_t seed) {
|
||||
if (length >= 4 && length <= 8)
|
||||
return hash_4to8_bytes(s, length, seed);
|
||||
if (length > 8 && length <= 16)
|
||||
return hash_9to16_bytes(s, length, seed);
|
||||
if (length > 16 && length <= 32)
|
||||
return hash_17to32_bytes(s, length, seed);
|
||||
if (length > 32)
|
||||
return hash_33to64_bytes(s, length, seed);
|
||||
if (length != 0)
|
||||
return hash_1to3_bytes(s, length, seed);
|
||||
|
||||
return k2 ^ seed;
|
||||
}
|
||||
|
||||
/// \brief The intermediate state used during hashing.
|
||||
/// Currently, the algorithm for computing hash codes is based on CityHash and
|
||||
/// keeps 56 bytes of arbitrary state.
|
||||
struct hash_state {
|
||||
uint64_t h0, h1, h2, h3, h4, h5, h6;
|
||||
|
||||
/// \brief Create a new hash_state structure and initialize it based on the
|
||||
/// seed and the first 64-byte chunk.
|
||||
/// This effectively performs the initial mix.
|
||||
static hash_state create(const char *s, uint64_t seed) {
|
||||
hash_state state = {
|
||||
0, seed, hash_16_bytes(seed, k1), rotate(seed ^ k1, 49),
|
||||
seed * k1, shift_mix(seed), 0 };
|
||||
state.h6 = hash_16_bytes(state.h4, state.h5);
|
||||
state.mix(s);
|
||||
return state;
|
||||
}
|
||||
|
||||
/// \brief Mix 32-bytes from the input sequence into the 16-bytes of 'a'
|
||||
/// and 'b', including whatever is already in 'a' and 'b'.
|
||||
static void mix_32_bytes(const char *s, uint64_t &a, uint64_t &b) {
|
||||
a += fetch64(s);
|
||||
uint64_t c = fetch64(s + 24);
|
||||
b = rotate(b + a + c, 21);
|
||||
uint64_t d = a;
|
||||
a += fetch64(s + 8) + fetch64(s + 16);
|
||||
b += rotate(a, 44) + d;
|
||||
a += c;
|
||||
}
|
||||
|
||||
/// \brief Mix in a 64-byte buffer of data.
|
||||
/// We mix all 64 bytes even when the chunk length is smaller, but we
|
||||
/// record the actual length.
|
||||
void mix(const char *s) {
|
||||
h0 = rotate(h0 + h1 + h3 + fetch64(s + 8), 37) * k1;
|
||||
h1 = rotate(h1 + h4 + fetch64(s + 48), 42) * k1;
|
||||
h0 ^= h6;
|
||||
h1 += h3 + fetch64(s + 40);
|
||||
h2 = rotate(h2 + h5, 33) * k1;
|
||||
h3 = h4 * k1;
|
||||
h4 = h0 + h5;
|
||||
mix_32_bytes(s, h3, h4);
|
||||
h5 = h2 + h6;
|
||||
h6 = h1 + fetch64(s + 16);
|
||||
mix_32_bytes(s + 32, h5, h6);
|
||||
std::swap(h2, h0);
|
||||
}
|
||||
|
||||
/// \brief Compute the final 64-bit hash code value based on the current
|
||||
/// state and the length of bytes hashed.
|
||||
uint64_t finalize(size_t length) {
|
||||
return hash_16_bytes(hash_16_bytes(h3, h5) + shift_mix(h1) * k1 + h2,
|
||||
hash_16_bytes(h4, h6) + shift_mix(length) * k1 + h0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// \brief A global, fixed seed-override variable.
|
||||
///
|
||||
/// This variable can be set using the \see llvm::set_fixed_execution_seed
|
||||
/// function. See that function for details. Do not, under any circumstances,
|
||||
/// set or read this variable.
|
||||
extern size_t fixed_seed_override;
|
||||
|
||||
inline size_t get_execution_seed() {
|
||||
// FIXME: This needs to be a per-execution seed. This is just a placeholder
|
||||
// implementation. Switching to a per-execution seed is likely to flush out
|
||||
// instability bugs and so will happen as its own commit.
|
||||
//
|
||||
// However, if there is a fixed seed override set the first time this is
|
||||
// called, return that instead of the per-execution seed.
|
||||
const uint64_t seed_prime = 0xff51afd7ed558ccdULL;
|
||||
static size_t seed = fixed_seed_override ? fixed_seed_override
|
||||
: (size_t)seed_prime;
|
||||
return seed;
|
||||
}
|
||||
|
||||
|
||||
/// \brief Trait to indicate whether a type's bits can be hashed directly.
|
||||
///
|
||||
/// A type trait which is true if we want to combine values for hashing by
|
||||
/// reading the underlying data. It is false if values of this type must
|
||||
/// first be passed to hash_value, and the resulting hash_codes combined.
|
||||
//
|
||||
// FIXME: We want to replace is_integral_or_enum and is_pointer here with
|
||||
// a predicate which asserts that comparing the underlying storage of two
|
||||
// values of the type for equality is equivalent to comparing the two values
|
||||
// for equality. For all the platforms we care about, this holds for integers
|
||||
// and pointers, but there are platforms where it doesn't and we would like to
|
||||
// support user-defined types which happen to satisfy this property.
|
||||
template <typename T> struct is_hashable_data
|
||||
: std::integral_constant<bool, ((is_integral_or_enum<T>::value ||
|
||||
std::is_pointer<T>::value) &&
|
||||
64 % sizeof(T) == 0)> {};
|
||||
|
||||
// Special case std::pair to detect when both types are viable and when there
|
||||
// is no alignment-derived padding in the pair. This is a bit of a lie because
|
||||
// std::pair isn't truly POD, but it's close enough in all reasonable
|
||||
// implementations for our use case of hashing the underlying data.
|
||||
template <typename T, typename U> struct is_hashable_data<std::pair<T, U> >
|
||||
: std::integral_constant<bool, (is_hashable_data<T>::value &&
|
||||
is_hashable_data<U>::value &&
|
||||
(sizeof(T) + sizeof(U)) ==
|
||||
sizeof(std::pair<T, U>))> {};
|
||||
|
||||
/// \brief Helper to get the hashable data representation for a type.
|
||||
/// This variant is enabled when the type itself can be used.
|
||||
template <typename T>
|
||||
typename std::enable_if<is_hashable_data<T>::value, T>::type
|
||||
get_hashable_data(const T &value) {
|
||||
return value;
|
||||
}
|
||||
/// \brief Helper to get the hashable data representation for a type.
|
||||
/// This variant is enabled when we must first call hash_value and use the
|
||||
/// result as our data.
|
||||
template <typename T>
|
||||
typename std::enable_if<!is_hashable_data<T>::value, size_t>::type
|
||||
get_hashable_data(const T &value) {
|
||||
using ::llvm::hash_value;
|
||||
return hash_value(value);
|
||||
}
|
||||
|
||||
/// \brief Helper to store data from a value into a buffer and advance the
|
||||
/// pointer into that buffer.
|
||||
///
|
||||
/// This routine first checks whether there is enough space in the provided
|
||||
/// buffer, and if not immediately returns false. If there is space, it
|
||||
/// copies the underlying bytes of value into the buffer, advances the
|
||||
/// buffer_ptr past the copied bytes, and returns true.
|
||||
template <typename T>
|
||||
bool store_and_advance(char *&buffer_ptr, char *buffer_end, const T& value,
|
||||
size_t offset = 0) {
|
||||
size_t store_size = sizeof(value) - offset;
|
||||
if (buffer_ptr + store_size > buffer_end)
|
||||
return false;
|
||||
const char *value_data = reinterpret_cast<const char *>(&value);
|
||||
memcpy(buffer_ptr, value_data + offset, store_size);
|
||||
buffer_ptr += store_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// \brief Implement the combining of integral values into a hash_code.
|
||||
///
|
||||
/// This overload is selected when the value type of the iterator is
|
||||
/// integral. Rather than computing a hash_code for each object and then
|
||||
/// combining them, this (as an optimization) directly combines the integers.
|
||||
template <typename InputIteratorT>
|
||||
hash_code hash_combine_range_impl(InputIteratorT first, InputIteratorT last) {
|
||||
const size_t seed = get_execution_seed();
|
||||
char buffer[64], *buffer_ptr = buffer;
|
||||
char *const buffer_end = std::end(buffer);
|
||||
while (first != last && store_and_advance(buffer_ptr, buffer_end,
|
||||
get_hashable_data(*first)))
|
||||
++first;
|
||||
if (first == last)
|
||||
return hash_short(buffer, buffer_ptr - buffer, seed);
|
||||
assert(buffer_ptr == buffer_end);
|
||||
|
||||
hash_state state = state.create(buffer, seed);
|
||||
size_t length = 64;
|
||||
while (first != last) {
|
||||
// Fill up the buffer. We don't clear it, which re-mixes the last round
|
||||
// when only a partial 64-byte chunk is left.
|
||||
buffer_ptr = buffer;
|
||||
while (first != last && store_and_advance(buffer_ptr, buffer_end,
|
||||
get_hashable_data(*first)))
|
||||
++first;
|
||||
|
||||
// Rotate the buffer if we did a partial fill in order to simulate doing
|
||||
// a mix of the last 64-bytes. That is how the algorithm works when we
|
||||
// have a contiguous byte sequence, and we want to emulate that here.
|
||||
std::rotate(buffer, buffer_ptr, buffer_end);
|
||||
|
||||
// Mix this chunk into the current state.
|
||||
state.mix(buffer);
|
||||
length += buffer_ptr - buffer;
|
||||
};
|
||||
|
||||
return state.finalize(length);
|
||||
}
|
||||
|
||||
/// \brief Implement the combining of integral values into a hash_code.
|
||||
///
|
||||
/// This overload is selected when the value type of the iterator is integral
|
||||
/// and when the input iterator is actually a pointer. Rather than computing
|
||||
/// a hash_code for each object and then combining them, this (as an
|
||||
/// optimization) directly combines the integers. Also, because the integers
|
||||
/// are stored in contiguous memory, this routine avoids copying each value
|
||||
/// and directly reads from the underlying memory.
|
||||
template <typename ValueT>
|
||||
typename std::enable_if<is_hashable_data<ValueT>::value, hash_code>::type
|
||||
hash_combine_range_impl(ValueT *first, ValueT *last) {
|
||||
const size_t seed = get_execution_seed();
|
||||
const char *s_begin = reinterpret_cast<const char *>(first);
|
||||
const char *s_end = reinterpret_cast<const char *>(last);
|
||||
const size_t length = std::distance(s_begin, s_end);
|
||||
if (length <= 64)
|
||||
return hash_short(s_begin, length, seed);
|
||||
|
||||
const char *s_aligned_end = s_begin + (length & ~63);
|
||||
hash_state state = state.create(s_begin, seed);
|
||||
s_begin += 64;
|
||||
while (s_begin != s_aligned_end) {
|
||||
state.mix(s_begin);
|
||||
s_begin += 64;
|
||||
}
|
||||
if (length & 63)
|
||||
state.mix(s_end - 64);
|
||||
|
||||
return state.finalize(length);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace hashing
|
||||
|
||||
|
||||
/// \brief Compute a hash_code for a sequence of values.
|
||||
///
|
||||
/// This hashes a sequence of values. It produces the same hash_code as
|
||||
/// 'hash_combine(a, b, c, ...)', but can run over arbitrary sized sequences
|
||||
/// and is significantly faster given pointers and types which can be hashed as
|
||||
/// a sequence of bytes.
|
||||
template <typename InputIteratorT>
|
||||
hash_code hash_combine_range(InputIteratorT first, InputIteratorT last) {
|
||||
return ::llvm::hashing::detail::hash_combine_range_impl(first, last);
|
||||
}
|
||||
|
||||
|
||||
// Implementation details for hash_combine.
|
||||
namespace hashing {
|
||||
namespace detail {
|
||||
|
||||
/// \brief Helper class to manage the recursive combining of hash_combine
|
||||
/// arguments.
|
||||
///
|
||||
/// This class exists to manage the state and various calls involved in the
|
||||
/// recursive combining of arguments used in hash_combine. It is particularly
|
||||
/// useful at minimizing the code in the recursive calls to ease the pain
|
||||
/// caused by a lack of variadic functions.
|
||||
struct hash_combine_recursive_helper {
|
||||
char buffer[64];
|
||||
hash_state state;
|
||||
const size_t seed;
|
||||
|
||||
public:
|
||||
/// \brief Construct a recursive hash combining helper.
|
||||
///
|
||||
/// This sets up the state for a recursive hash combine, including getting
|
||||
/// the seed and buffer setup.
|
||||
hash_combine_recursive_helper()
|
||||
: seed(get_execution_seed()) {}
|
||||
|
||||
/// \brief Combine one chunk of data into the current in-flight hash.
|
||||
///
|
||||
/// This merges one chunk of data into the hash. First it tries to buffer
|
||||
/// the data. If the buffer is full, it hashes the buffer into its
|
||||
/// hash_state, empties it, and then merges the new chunk in. This also
|
||||
/// handles cases where the data straddles the end of the buffer.
|
||||
template <typename T>
|
||||
char *combine_data(size_t &length, char *buffer_ptr, char *buffer_end, T data) {
|
||||
if (!store_and_advance(buffer_ptr, buffer_end, data)) {
|
||||
// Check for skew which prevents the buffer from being packed, and do
|
||||
// a partial store into the buffer to fill it. This is only a concern
|
||||
// with the variadic combine because that formation can have varying
|
||||
// argument types.
|
||||
size_t partial_store_size = buffer_end - buffer_ptr;
|
||||
memcpy(buffer_ptr, &data, partial_store_size);
|
||||
|
||||
// If the store fails, our buffer is full and ready to hash. We have to
|
||||
// either initialize the hash state (on the first full buffer) or mix
|
||||
// this buffer into the existing hash state. Length tracks the *hashed*
|
||||
// length, not the buffered length.
|
||||
if (length == 0) {
|
||||
state = state.create(buffer, seed);
|
||||
length = 64;
|
||||
} else {
|
||||
// Mix this chunk into the current state and bump length up by 64.
|
||||
state.mix(buffer);
|
||||
length += 64;
|
||||
}
|
||||
// Reset the buffer_ptr to the head of the buffer for the next chunk of
|
||||
// data.
|
||||
buffer_ptr = buffer;
|
||||
|
||||
// Try again to store into the buffer -- this cannot fail as we only
|
||||
// store types smaller than the buffer.
|
||||
if (!store_and_advance(buffer_ptr, buffer_end, data,
|
||||
partial_store_size))
|
||||
abort();
|
||||
}
|
||||
return buffer_ptr;
|
||||
}
|
||||
|
||||
/// \brief Recursive, variadic combining method.
|
||||
///
|
||||
/// This function recurses through each argument, combining that argument
|
||||
/// into a single hash.
|
||||
template <typename T, typename ...Ts>
|
||||
hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
|
||||
const T &arg, const Ts &...args) {
|
||||
buffer_ptr = combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg));
|
||||
|
||||
// Recurse to the next argument.
|
||||
return combine(length, buffer_ptr, buffer_end, args...);
|
||||
}
|
||||
|
||||
/// \brief Base case for recursive, variadic combining.
|
||||
///
|
||||
/// The base case when combining arguments recursively is reached when all
|
||||
/// arguments have been handled. It flushes the remaining buffer and
|
||||
/// constructs a hash_code.
|
||||
hash_code combine(size_t length, char *buffer_ptr, char *buffer_end) {
|
||||
// Check whether the entire set of values fit in the buffer. If so, we'll
|
||||
// use the optimized short hashing routine and skip state entirely.
|
||||
if (length == 0)
|
||||
return hash_short(buffer, buffer_ptr - buffer, seed);
|
||||
|
||||
// Mix the final buffer, rotating it if we did a partial fill in order to
|
||||
// simulate doing a mix of the last 64-bytes. That is how the algorithm
|
||||
// works when we have a contiguous byte sequence, and we want to emulate
|
||||
// that here.
|
||||
std::rotate(buffer, buffer_ptr, buffer_end);
|
||||
|
||||
// Mix this chunk into the current state.
|
||||
state.mix(buffer);
|
||||
length += buffer_ptr - buffer;
|
||||
|
||||
return state.finalize(length);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace hashing
|
||||
|
||||
/// \brief Combine values into a single hash_code.
|
||||
///
|
||||
/// This routine accepts a varying number of arguments of any type. It will
|
||||
/// attempt to combine them into a single hash_code. For user-defined types it
|
||||
/// attempts to call a \see hash_value overload (via ADL) for the type. For
|
||||
/// integer and pointer types it directly combines their data into the
|
||||
/// resulting hash_code.
|
||||
///
|
||||
/// The result is suitable for returning from a user's hash_value
|
||||
/// *implementation* for their user-defined type. Consumers of a type should
|
||||
/// *not* call this routine, they should instead call 'hash_value'.
|
||||
template <typename ...Ts> hash_code hash_combine(const Ts &...args) {
|
||||
// Recursively hash each argument using a helper class.
|
||||
::llvm::hashing::detail::hash_combine_recursive_helper helper;
|
||||
return helper.combine(0, helper.buffer, helper.buffer + 64, args...);
|
||||
}
|
||||
|
||||
// Implementation details for implementations of hash_value overloads provided
|
||||
// here.
|
||||
namespace hashing {
|
||||
namespace detail {
|
||||
|
||||
/// \brief Helper to hash the value of a single integer.
|
||||
///
|
||||
/// Overloads for smaller integer types are not provided to ensure consistent
|
||||
/// behavior in the presence of integral promotions. Essentially,
|
||||
/// "hash_value('4')" and "hash_value('0' + 4)" should be the same.
|
||||
inline hash_code hash_integer_value(uint64_t value) {
|
||||
// Similar to hash_4to8_bytes but using a seed instead of length.
|
||||
const uint64_t seed = get_execution_seed();
|
||||
const char *s = reinterpret_cast<const char *>(&value);
|
||||
const uint64_t a = fetch32(s);
|
||||
return hash_16_bytes(seed + (a << 3), fetch32(s + 4));
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace hashing
|
||||
|
||||
// Declared and documented above, but defined here so that any of the hashing
|
||||
// infrastructure is available.
|
||||
template <typename T>
|
||||
typename std::enable_if<is_integral_or_enum<T>::value, hash_code>::type
|
||||
hash_value(T value) {
|
||||
return ::llvm::hashing::detail::hash_integer_value(
|
||||
static_cast<uint64_t>(value));
|
||||
}
|
||||
|
||||
// Declared and documented above, but defined here so that any of the hashing
|
||||
// infrastructure is available.
|
||||
template <typename T> hash_code hash_value(const T *ptr) {
|
||||
return ::llvm::hashing::detail::hash_integer_value(
|
||||
reinterpret_cast<uintptr_t>(ptr));
|
||||
}
|
||||
|
||||
// Declared and documented above, but defined here so that any of the hashing
|
||||
// infrastructure is available.
|
||||
template <typename T, typename U>
|
||||
hash_code hash_value(const std::pair<T, U> &arg) {
|
||||
return hash_combine(arg.first, arg.second);
|
||||
}
|
||||
|
||||
// Declared and documented above, but defined here so that any of the hashing
|
||||
// infrastructure is available.
|
||||
template <typename T>
|
||||
hash_code hash_value(const std::basic_string<T> &arg) {
|
||||
return hash_combine_range(arg.begin(), arg.end());
|
||||
}
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
653
src/main/native/include/llvm/MathExtras.h
Normal file
653
src/main/native/include/llvm/MathExtras.h
Normal file
@@ -0,0 +1,653 @@
|
||||
//===-- llvm/Support/MathExtras.h - Useful math functions -------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains some functions that are useful for math stuff.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_MATHEXTRAS_H
|
||||
#define LLVM_SUPPORT_MATHEXTRAS_H
|
||||
|
||||
#include "llvm/Compiler.h"
|
||||
#include <cstdint>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <type_traits>
|
||||
#include <limits>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
namespace llvm {
|
||||
/// \brief The behavior an operation has on an input of 0.
|
||||
enum ZeroBehavior {
|
||||
/// \brief The returned value is undefined.
|
||||
ZB_Undefined,
|
||||
/// \brief The returned value is numeric_limits<T>::max()
|
||||
ZB_Max,
|
||||
/// \brief The returned value is numeric_limits<T>::digits
|
||||
ZB_Width
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
template <typename T, std::size_t SizeOfT> struct LeadingZerosCounter {
|
||||
static std::size_t count(T Val, ZeroBehavior) {
|
||||
if (!Val)
|
||||
return std::numeric_limits<T>::digits;
|
||||
|
||||
// Bisection method.
|
||||
std::size_t ZeroBits = 0;
|
||||
for (T Shift = std::numeric_limits<T>::digits >> 1; Shift; Shift >>= 1) {
|
||||
T Tmp = Val >> Shift;
|
||||
if (Tmp)
|
||||
Val = Tmp;
|
||||
else
|
||||
ZeroBits |= Shift;
|
||||
}
|
||||
return ZeroBits;
|
||||
}
|
||||
};
|
||||
|
||||
#if __GNUC__ >= 4 || defined(_MSC_VER)
|
||||
template <typename T> struct LeadingZerosCounter<T, 4> {
|
||||
static std::size_t count(T Val, ZeroBehavior ZB) {
|
||||
if (ZB != ZB_Undefined && Val == 0)
|
||||
return 32;
|
||||
|
||||
#if __has_builtin(__builtin_clz) || LLVM_GNUC_PREREQ(4, 0, 0)
|
||||
return __builtin_clz(Val);
|
||||
#elif defined(_MSC_VER)
|
||||
unsigned long Index;
|
||||
_BitScanReverse(&Index, Val);
|
||||
return Index ^ 31;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#if !defined(_MSC_VER) || defined(_M_X64)
|
||||
template <typename T> struct LeadingZerosCounter<T, 8> {
|
||||
static std::size_t count(T Val, ZeroBehavior ZB) {
|
||||
if (ZB != ZB_Undefined && Val == 0)
|
||||
return 64;
|
||||
|
||||
#if __has_builtin(__builtin_clzll) || LLVM_GNUC_PREREQ(4, 0, 0)
|
||||
return __builtin_clzll(Val);
|
||||
#elif defined(_MSC_VER)
|
||||
unsigned long Index;
|
||||
_BitScanReverse64(&Index, Val);
|
||||
return Index ^ 63;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
} // namespace detail
|
||||
|
||||
/// \brief Count number of 0's from the most significant bit to the least
|
||||
/// stopping at the first 1.
|
||||
///
|
||||
/// Only unsigned integral types are allowed.
|
||||
///
|
||||
/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are
|
||||
/// valid arguments.
|
||||
template <typename T>
|
||||
std::size_t countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
|
||||
static_assert(std::numeric_limits<T>::is_integer &&
|
||||
!std::numeric_limits<T>::is_signed,
|
||||
"Only unsigned integral types are allowed.");
|
||||
return detail::LeadingZerosCounter<T, sizeof(T)>::count(Val, ZB);
|
||||
}
|
||||
|
||||
/// \brief Get the index of the last set bit starting from the least
|
||||
/// significant bit.
|
||||
///
|
||||
/// Only unsigned integral types are allowed.
|
||||
///
|
||||
/// \param ZB the behavior on an input of 0. Only ZB_Max and ZB_Undefined are
|
||||
/// valid arguments.
|
||||
template <typename T> T findLastSet(T Val, ZeroBehavior ZB = ZB_Max) {
|
||||
if (ZB == ZB_Max && Val == 0)
|
||||
return std::numeric_limits<T>::max();
|
||||
|
||||
// Use ^ instead of - because both gcc and llvm can remove the associated ^
|
||||
// in the __builtin_clz intrinsic on x86.
|
||||
return countLeadingZeros(Val, ZB_Undefined) ^
|
||||
(std::numeric_limits<T>::digits - 1);
|
||||
}
|
||||
|
||||
/// \brief Macro compressed bit reversal table for 256 bits.
|
||||
///
|
||||
/// http://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable
|
||||
static const unsigned char BitReverseTable256[256] = {
|
||||
#define R2(n) n, n + 2 * 64, n + 1 * 64, n + 3 * 64
|
||||
#define R4(n) R2(n), R2(n + 2 * 16), R2(n + 1 * 16), R2(n + 3 * 16)
|
||||
#define R6(n) R4(n), R4(n + 2 * 4), R4(n + 1 * 4), R4(n + 3 * 4)
|
||||
R6(0), R6(2), R6(1), R6(3)
|
||||
#undef R2
|
||||
#undef R4
|
||||
#undef R6
|
||||
};
|
||||
|
||||
/// \brief Reverse the bits in \p Val.
|
||||
template <typename T>
|
||||
T reverseBits(T Val) {
|
||||
unsigned char in[sizeof(Val)];
|
||||
unsigned char out[sizeof(Val)];
|
||||
std::memcpy(in, &Val, sizeof(Val));
|
||||
for (unsigned i = 0; i < sizeof(Val); ++i)
|
||||
out[(sizeof(Val) - i) - 1] = BitReverseTable256[in[i]];
|
||||
std::memcpy(&Val, out, sizeof(Val));
|
||||
return Val;
|
||||
}
|
||||
|
||||
// NOTE: The following support functions use the _32/_64 extensions instead of
|
||||
// type overloading so that signed and unsigned integers can be used without
|
||||
// ambiguity.
|
||||
|
||||
/// Hi_32 - This function returns the high 32 bits of a 64 bit value.
|
||||
inline uint32_t Hi_32(uint64_t Value) {
|
||||
return static_cast<uint32_t>(Value >> 32);
|
||||
}
|
||||
|
||||
/// Lo_32 - This function returns the low 32 bits of a 64 bit value.
|
||||
inline uint32_t Lo_32(uint64_t Value) {
|
||||
return static_cast<uint32_t>(Value);
|
||||
}
|
||||
|
||||
/// Make_64 - This functions makes a 64-bit integer from a high / low pair of
|
||||
/// 32-bit integers.
|
||||
inline uint64_t Make_64(uint32_t High, uint32_t Low) {
|
||||
return ((uint64_t)High << 32) | (uint64_t)Low;
|
||||
}
|
||||
|
||||
/// isInt - Checks if an integer fits into the given bit width.
|
||||
template<unsigned N>
|
||||
inline bool isInt(int64_t x) {
|
||||
return N >= 64 || (-(INT64_C(1)<<(N-1)) <= x && x < (INT64_C(1)<<(N-1)));
|
||||
}
|
||||
// Template specializations to get better code for common cases.
|
||||
template<>
|
||||
inline bool isInt<8>(int64_t x) {
|
||||
return static_cast<int8_t>(x) == x;
|
||||
}
|
||||
template<>
|
||||
inline bool isInt<16>(int64_t x) {
|
||||
return static_cast<int16_t>(x) == x;
|
||||
}
|
||||
template<>
|
||||
inline bool isInt<32>(int64_t x) {
|
||||
return static_cast<int32_t>(x) == x;
|
||||
}
|
||||
|
||||
/// isShiftedInt<N,S> - Checks if a signed integer is an N bit number shifted
|
||||
/// left by S.
|
||||
template<unsigned N, unsigned S>
|
||||
inline bool isShiftedInt(int64_t x) {
|
||||
return isInt<N+S>(x) && (x % (1<<S) == 0);
|
||||
}
|
||||
|
||||
/// isUInt - Checks if an unsigned integer fits into the given bit width.
|
||||
template<unsigned N>
|
||||
inline bool isUInt(uint64_t x) {
|
||||
return N >= 64 || x < (UINT64_C(1)<<(N));
|
||||
}
|
||||
// Template specializations to get better code for common cases.
|
||||
template<>
|
||||
inline bool isUInt<8>(uint64_t x) {
|
||||
return static_cast<uint8_t>(x) == x;
|
||||
}
|
||||
template<>
|
||||
inline bool isUInt<16>(uint64_t x) {
|
||||
return static_cast<uint16_t>(x) == x;
|
||||
}
|
||||
template<>
|
||||
inline bool isUInt<32>(uint64_t x) {
|
||||
return static_cast<uint32_t>(x) == x;
|
||||
}
|
||||
|
||||
/// isShiftedUInt<N,S> - Checks if a unsigned integer is an N bit number shifted
|
||||
/// left by S.
|
||||
template<unsigned N, unsigned S>
|
||||
inline bool isShiftedUInt(uint64_t x) {
|
||||
return isUInt<N+S>(x) && (x % (1<<S) == 0);
|
||||
}
|
||||
|
||||
/// Gets the maximum value for a N-bit unsigned integer.
|
||||
inline uint64_t maxUIntN(uint64_t N) {
|
||||
assert(N > 0 && N <= 64 && "integer width out of range");
|
||||
|
||||
return (UINT64_C(1) << N) - 1;
|
||||
}
|
||||
|
||||
/// Gets the minimum value for a N-bit signed integer.
|
||||
inline int64_t minIntN(int64_t N) {
|
||||
assert(N > 0 && N <= 64 && "integer width out of range");
|
||||
|
||||
return -(INT64_C(1)<<(N-1));
|
||||
}
|
||||
|
||||
/// Gets the maximum value for a N-bit signed integer.
|
||||
inline int64_t maxIntN(int64_t N) {
|
||||
assert(N > 0 && N <= 64 && "integer width out of range");
|
||||
|
||||
return (INT64_C(1)<<(N-1)) - 1;
|
||||
}
|
||||
|
||||
/// isUIntN - Checks if an unsigned integer fits into the given (dynamic)
|
||||
/// bit width.
|
||||
inline bool isUIntN(unsigned N, uint64_t x) {
|
||||
return N >= 64 || x <= maxUIntN(N);
|
||||
}
|
||||
|
||||
/// isIntN - Checks if an signed integer fits into the given (dynamic)
|
||||
/// bit width.
|
||||
inline bool isIntN(unsigned N, int64_t x) {
|
||||
return N >= 64 || (minIntN(N) <= x && x <= maxIntN(N));
|
||||
}
|
||||
|
||||
/// isMask_32 - This function returns true if the argument is a non-empty
|
||||
/// sequence of ones starting at the least significant bit with the remainder
|
||||
/// zero (32 bit version). Ex. isMask_32(0x0000FFFFU) == true.
|
||||
inline bool isMask_32(uint32_t Value) {
|
||||
return Value && ((Value + 1) & Value) == 0;
|
||||
}
|
||||
|
||||
/// isMask_64 - This function returns true if the argument is a non-empty
|
||||
/// sequence of ones starting at the least significant bit with the remainder
|
||||
/// zero (64 bit version).
|
||||
inline bool isMask_64(uint64_t Value) {
|
||||
return Value && ((Value + 1) & Value) == 0;
|
||||
}
|
||||
|
||||
/// isShiftedMask_32 - This function returns true if the argument contains a
|
||||
/// non-empty sequence of ones with the remainder zero (32 bit version.)
|
||||
/// Ex. isShiftedMask_32(0x0000FF00U) == true.
|
||||
inline bool isShiftedMask_32(uint32_t Value) {
|
||||
return Value && isMask_32((Value - 1) | Value);
|
||||
}
|
||||
|
||||
/// isShiftedMask_64 - This function returns true if the argument contains a
|
||||
/// non-empty sequence of ones with the remainder zero (64 bit version.)
|
||||
inline bool isShiftedMask_64(uint64_t Value) {
|
||||
return Value && isMask_64((Value - 1) | Value);
|
||||
}
|
||||
|
||||
/// isPowerOf2_32 - This function returns true if the argument is a power of
|
||||
/// two > 0. Ex. isPowerOf2_32(0x00100000U) == true (32 bit edition.)
|
||||
inline bool isPowerOf2_32(uint32_t Value) {
|
||||
return Value && !(Value & (Value - 1));
|
||||
}
|
||||
|
||||
/// isPowerOf2_64 - This function returns true if the argument is a power of two
|
||||
/// > 0 (64 bit edition.)
|
||||
inline bool isPowerOf2_64(uint64_t Value) {
|
||||
return Value && !(Value & (Value - int64_t(1L)));
|
||||
}
|
||||
|
||||
/// \brief Count the number of ones from the most significant bit to the first
|
||||
/// zero bit.
|
||||
///
|
||||
/// Ex. CountLeadingOnes(0xFF0FFF00) == 8.
|
||||
/// Only unsigned integral types are allowed.
|
||||
///
|
||||
/// \param ZB the behavior on an input of all ones. Only ZB_Width and
|
||||
/// ZB_Undefined are valid arguments.
|
||||
template <typename T>
|
||||
std::size_t countLeadingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
|
||||
static_assert(std::numeric_limits<T>::is_integer &&
|
||||
!std::numeric_limits<T>::is_signed,
|
||||
"Only unsigned integral types are allowed.");
|
||||
return countLeadingZeros(~Value, ZB);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template <typename T, std::size_t SizeOfT> struct PopulationCounter {
|
||||
static unsigned count(T Value) {
|
||||
// Generic version, forward to 32 bits.
|
||||
static_assert(SizeOfT <= 4, "Not implemented!");
|
||||
#if __GNUC__ >= 4
|
||||
return __builtin_popcount(Value);
|
||||
#else
|
||||
uint32_t v = Value;
|
||||
v = v - ((v >> 1) & 0x55555555);
|
||||
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
|
||||
return ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> struct PopulationCounter<T, 8> {
|
||||
static unsigned count(T Value) {
|
||||
#if __GNUC__ >= 4
|
||||
return __builtin_popcountll(Value);
|
||||
#else
|
||||
uint64_t v = Value;
|
||||
v = v - ((v >> 1) & 0x5555555555555555ULL);
|
||||
v = (v & 0x3333333333333333ULL) + ((v >> 2) & 0x3333333333333333ULL);
|
||||
v = (v + (v >> 4)) & 0x0F0F0F0F0F0F0F0FULL;
|
||||
return unsigned((uint64_t)(v * 0x0101010101010101ULL) >> 56);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
/// \brief Count the number of set bits in a value.
|
||||
/// Ex. countPopulation(0xF000F000) = 8
|
||||
/// Returns 0 if the word is zero.
|
||||
template <typename T>
|
||||
inline unsigned countPopulation(T Value) {
|
||||
static_assert(std::numeric_limits<T>::is_integer &&
|
||||
!std::numeric_limits<T>::is_signed,
|
||||
"Only unsigned integral types are allowed.");
|
||||
return detail::PopulationCounter<T, sizeof(T)>::count(Value);
|
||||
}
|
||||
|
||||
/// Log2 - This function returns the log base 2 of the specified value
|
||||
inline double Log2(double Value) {
|
||||
#if defined(__ANDROID_API__) && __ANDROID_API__ < 18
|
||||
return __builtin_log(Value) / __builtin_log(2.0);
|
||||
#else
|
||||
return std::log2(Value);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Log2_32 - This function returns the floor log base 2 of the specified value,
|
||||
/// -1 if the value is zero. (32 bit edition.)
|
||||
/// Ex. Log2_32(32) == 5, Log2_32(1) == 0, Log2_32(0) == -1, Log2_32(6) == 2
|
||||
inline unsigned Log2_32(uint32_t Value) {
|
||||
return 31 - countLeadingZeros(Value);
|
||||
}
|
||||
|
||||
/// Log2_64 - This function returns the floor log base 2 of the specified value,
|
||||
/// -1 if the value is zero. (64 bit edition.)
|
||||
inline unsigned Log2_64(uint64_t Value) {
|
||||
return 63 - countLeadingZeros(Value);
|
||||
}
|
||||
|
||||
/// Log2_32_Ceil - This function returns the ceil log base 2 of the specified
|
||||
/// value, 32 if the value is zero. (32 bit edition).
|
||||
/// Ex. Log2_32_Ceil(32) == 5, Log2_32_Ceil(1) == 0, Log2_32_Ceil(6) == 3
|
||||
inline unsigned Log2_32_Ceil(uint32_t Value) {
|
||||
return 32 - countLeadingZeros(Value - 1);
|
||||
}
|
||||
|
||||
/// Log2_64_Ceil - This function returns the ceil log base 2 of the specified
|
||||
/// value, 64 if the value is zero. (64 bit edition.)
|
||||
inline unsigned Log2_64_Ceil(uint64_t Value) {
|
||||
return 64 - countLeadingZeros(Value - 1);
|
||||
}
|
||||
|
||||
/// GreatestCommonDivisor64 - Return the greatest common divisor of the two
|
||||
/// values using Euclid's algorithm.
|
||||
inline uint64_t GreatestCommonDivisor64(uint64_t A, uint64_t B) {
|
||||
while (B) {
|
||||
uint64_t T = B;
|
||||
B = A % B;
|
||||
A = T;
|
||||
}
|
||||
return A;
|
||||
}
|
||||
|
||||
/// BitsToDouble - This function takes a 64-bit integer and returns the bit
|
||||
/// equivalent double.
|
||||
inline double BitsToDouble(uint64_t Bits) {
|
||||
union {
|
||||
uint64_t L;
|
||||
double D;
|
||||
} T;
|
||||
T.L = Bits;
|
||||
return T.D;
|
||||
}
|
||||
|
||||
/// BitsToFloat - This function takes a 32-bit integer and returns the bit
|
||||
/// equivalent float.
|
||||
inline float BitsToFloat(uint32_t Bits) {
|
||||
union {
|
||||
uint32_t I;
|
||||
float F;
|
||||
} T;
|
||||
T.I = Bits;
|
||||
return T.F;
|
||||
}
|
||||
|
||||
/// DoubleToBits - This function takes a double and returns the bit
|
||||
/// equivalent 64-bit integer. Note that copying doubles around
|
||||
/// changes the bits of NaNs on some hosts, notably x86, so this
|
||||
/// routine cannot be used if these bits are needed.
|
||||
inline uint64_t DoubleToBits(double Double) {
|
||||
union {
|
||||
uint64_t L;
|
||||
double D;
|
||||
} T;
|
||||
T.D = Double;
|
||||
return T.L;
|
||||
}
|
||||
|
||||
/// FloatToBits - This function takes a float and returns the bit
|
||||
/// equivalent 32-bit integer. Note that copying floats around
|
||||
/// changes the bits of NaNs on some hosts, notably x86, so this
|
||||
/// routine cannot be used if these bits are needed.
|
||||
inline uint32_t FloatToBits(float Float) {
|
||||
union {
|
||||
uint32_t I;
|
||||
float F;
|
||||
} T;
|
||||
T.F = Float;
|
||||
return T.I;
|
||||
}
|
||||
|
||||
/// MinAlign - A and B are either alignments or offsets. Return the minimum
|
||||
/// alignment that may be assumed after adding the two together.
|
||||
inline uint64_t MinAlign(uint64_t A, uint64_t B) {
|
||||
// The largest power of 2 that divides both A and B.
|
||||
//
|
||||
// Replace "-Value" by "1+~Value" in the following commented code to avoid
|
||||
// MSVC warning C4146
|
||||
// return (A | B) & -(A | B);
|
||||
return (A | B) & (1 + ~(A | B));
|
||||
}
|
||||
|
||||
/// \brief Aligns \c Addr to \c Alignment bytes, rounding up.
|
||||
///
|
||||
/// Alignment should be a power of two. This method rounds up, so
|
||||
/// alignAddr(7, 4) == 8 and alignAddr(8, 4) == 8.
|
||||
inline uintptr_t alignAddr(const void *Addr, size_t Alignment) {
|
||||
assert(Alignment && isPowerOf2_64((uint64_t)Alignment) &&
|
||||
"Alignment is not a power of two!");
|
||||
|
||||
assert((uintptr_t)Addr + Alignment - 1 >= (uintptr_t)Addr);
|
||||
|
||||
return (((uintptr_t)Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1));
|
||||
}
|
||||
|
||||
/// \brief Returns the necessary adjustment for aligning \c Ptr to \c Alignment
|
||||
/// bytes, rounding up.
|
||||
inline size_t alignmentAdjustment(const void *Ptr, size_t Alignment) {
|
||||
return alignAddr(Ptr, Alignment) - (uintptr_t)Ptr;
|
||||
}
|
||||
|
||||
/// NextPowerOf2 - Returns the next power of two (in 64-bits)
|
||||
/// that is strictly greater than A. Returns zero on overflow.
|
||||
inline uint64_t NextPowerOf2(uint64_t A) {
|
||||
A |= (A >> 1);
|
||||
A |= (A >> 2);
|
||||
A |= (A >> 4);
|
||||
A |= (A >> 8);
|
||||
A |= (A >> 16);
|
||||
A |= (A >> 32);
|
||||
return A + 1;
|
||||
}
|
||||
|
||||
/// Returns the power of two which is less than or equal to the given value.
|
||||
/// Essentially, it is a floor operation across the domain of powers of two.
|
||||
inline uint64_t PowerOf2Floor(uint64_t A) {
|
||||
if (!A) return 0;
|
||||
return 1ull << (63 - countLeadingZeros(A, ZB_Undefined));
|
||||
}
|
||||
|
||||
/// Returns the next integer (mod 2**64) that is greater than or equal to
|
||||
/// \p Value and is a multiple of \p Align. \p Align must be non-zero.
|
||||
///
|
||||
/// If non-zero \p Skew is specified, the return value will be a minimal
|
||||
/// integer that is greater than or equal to \p Value and equal to
|
||||
/// \p Align * N + \p Skew for some integer N. If \p Skew is larger than
|
||||
/// \p Align, its value is adjusted to '\p Skew mod \p Align'.
|
||||
///
|
||||
/// Examples:
|
||||
/// \code
|
||||
/// alignTo(5, 8) = 8
|
||||
/// alignTo(17, 8) = 24
|
||||
/// alignTo(~0LL, 8) = 0
|
||||
/// alignTo(321, 255) = 510
|
||||
///
|
||||
/// alignTo(5, 8, 7) = 7
|
||||
/// alignTo(17, 8, 1) = 17
|
||||
/// alignTo(~0LL, 8, 3) = 3
|
||||
/// alignTo(321, 255, 42) = 552
|
||||
/// \endcode
|
||||
inline uint64_t alignTo(uint64_t Value, uint64_t Align, uint64_t Skew = 0) {
|
||||
Skew %= Align;
|
||||
return (Value + Align - 1 - Skew) / Align * Align + Skew;
|
||||
}
|
||||
|
||||
/// Returns the largest uint64_t less than or equal to \p Value and is
|
||||
/// \p Skew mod \p Align. \p Align must be non-zero
|
||||
inline uint64_t alignDown(uint64_t Value, uint64_t Align, uint64_t Skew = 0) {
|
||||
Skew %= Align;
|
||||
return (Value - Skew) / Align * Align + Skew;
|
||||
}
|
||||
|
||||
/// Returns the offset to the next integer (mod 2**64) that is greater than
|
||||
/// or equal to \p Value and is a multiple of \p Align. \p Align must be
|
||||
/// non-zero.
|
||||
inline uint64_t OffsetToAlignment(uint64_t Value, uint64_t Align) {
|
||||
return alignTo(Value, Align) - Value;
|
||||
}
|
||||
|
||||
/// SignExtend32 - Sign extend B-bit number x to 32-bit int.
|
||||
/// Usage int32_t r = SignExtend32<5>(x);
|
||||
template <unsigned B> inline int32_t SignExtend32(uint32_t x) {
|
||||
return int32_t(x << (32 - B)) >> (32 - B);
|
||||
}
|
||||
|
||||
/// \brief Sign extend number in the bottom B bits of X to a 32-bit int.
|
||||
/// Requires 0 < B <= 32.
|
||||
inline int32_t SignExtend32(uint32_t X, unsigned B) {
|
||||
return int32_t(X << (32 - B)) >> (32 - B);
|
||||
}
|
||||
|
||||
/// SignExtend64 - Sign extend B-bit number x to 64-bit int.
|
||||
/// Usage int64_t r = SignExtend64<5>(x);
|
||||
template <unsigned B> inline int64_t SignExtend64(uint64_t x) {
|
||||
return int64_t(x << (64 - B)) >> (64 - B);
|
||||
}
|
||||
|
||||
/// \brief Sign extend number in the bottom B bits of X to a 64-bit int.
|
||||
/// Requires 0 < B <= 64.
|
||||
inline int64_t SignExtend64(uint64_t X, unsigned B) {
|
||||
return int64_t(X << (64 - B)) >> (64 - B);
|
||||
}
|
||||
|
||||
/// \brief Subtract two unsigned integers, X and Y, of type T and return their
|
||||
/// absolute value.
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_unsigned<T>::value, T>::type
|
||||
AbsoluteDifference(T X, T Y) {
|
||||
return std::max(X, Y) - std::min(X, Y);
|
||||
}
|
||||
|
||||
/// \brief Add two unsigned integers, X and Y, of type T.
|
||||
/// Clamp the result to the maximum representable value of T on overflow.
|
||||
/// ResultOverflowed indicates if the result is larger than the maximum
|
||||
/// representable value of type T.
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_unsigned<T>::value, T>::type
|
||||
SaturatingAdd(T X, T Y, bool *ResultOverflowed = nullptr) {
|
||||
bool Dummy;
|
||||
bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
|
||||
// Hacker's Delight, p. 29
|
||||
T Z = X + Y;
|
||||
Overflowed = (Z < X || Z < Y);
|
||||
if (Overflowed)
|
||||
return std::numeric_limits<T>::max();
|
||||
else
|
||||
return Z;
|
||||
}
|
||||
|
||||
/// \brief Multiply two unsigned integers, X and Y, of type T.
|
||||
/// Clamp the result to the maximum representable value of T on overflow.
|
||||
/// ResultOverflowed indicates if the result is larger than the maximum
|
||||
/// representable value of type T.
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_unsigned<T>::value, T>::type
|
||||
SaturatingMultiply(T X, T Y, bool *ResultOverflowed = nullptr) {
|
||||
bool Dummy;
|
||||
bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
|
||||
|
||||
// Hacker's Delight, p. 30 has a different algorithm, but we don't use that
|
||||
// because it fails for uint16_t (where multiplication can have undefined
|
||||
// behavior due to promotion to int), and requires a division in addition
|
||||
// to the multiplication.
|
||||
|
||||
Overflowed = false;
|
||||
|
||||
// Log2(Z) would be either Log2Z or Log2Z + 1.
|
||||
// Special case: if X or Y is 0, Log2_64 gives -1, and Log2Z
|
||||
// will necessarily be less than Log2Max as desired.
|
||||
int Log2Z = Log2_64(X) + Log2_64(Y);
|
||||
const T Max = std::numeric_limits<T>::max();
|
||||
int Log2Max = Log2_64(Max);
|
||||
if (Log2Z < Log2Max) {
|
||||
return X * Y;
|
||||
}
|
||||
if (Log2Z > Log2Max) {
|
||||
Overflowed = true;
|
||||
return Max;
|
||||
}
|
||||
|
||||
// We're going to use the top bit, and maybe overflow one
|
||||
// bit past it. Multiply all but the bottom bit then add
|
||||
// that on at the end.
|
||||
T Z = (X >> 1) * Y;
|
||||
if (Z & ~(Max >> 1)) {
|
||||
Overflowed = true;
|
||||
return Max;
|
||||
}
|
||||
Z <<= 1;
|
||||
if (X & 1)
|
||||
return SaturatingAdd(Z, Y, ResultOverflowed);
|
||||
|
||||
return Z;
|
||||
}
|
||||
|
||||
/// \brief Multiply two unsigned integers, X and Y, and add the unsigned
|
||||
/// integer, A to the product. Clamp the result to the maximum representable
|
||||
/// value of T on overflow. ResultOverflowed indicates if the result is larger
|
||||
/// than the maximum representable value of type T.
|
||||
/// Note that this is purely a convenience function as there is no distinction
|
||||
/// where overflow occurred in a 'fused' multiply-add for unsigned numbers.
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_unsigned<T>::value, T>::type
|
||||
SaturatingMultiplyAdd(T X, T Y, T A, bool *ResultOverflowed = nullptr) {
|
||||
bool Dummy;
|
||||
bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
|
||||
|
||||
T Product = SaturatingMultiply(X, Y, &Overflowed);
|
||||
if (Overflowed)
|
||||
return Product;
|
||||
|
||||
return SaturatingAdd(A, Product, &Overflowed);
|
||||
}
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
26
src/main/native/include/llvm/None.h
Normal file
26
src/main/native/include/llvm/None.h
Normal file
@@ -0,0 +1,26 @@
|
||||
//===-- None.h - Simple null value for implicit construction ------*- C++ -*-=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file provides None, an enumerator for use in implicit constructors
|
||||
// of various (usually templated) types to make such construction more
|
||||
// terse.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_NONE_H
|
||||
#define LLVM_ADT_NONE_H
|
||||
|
||||
namespace llvm {
|
||||
/// \brief A simple null object to allow implicit construction of Optional<T>
|
||||
/// and similar types without having to spell out the specialization's name.
|
||||
enum class NoneType { None };
|
||||
const NoneType None = None;
|
||||
}
|
||||
|
||||
#endif
|
||||
228
src/main/native/include/llvm/Optional.h
Normal file
228
src/main/native/include/llvm/Optional.h
Normal file
@@ -0,0 +1,228 @@
|
||||
//===-- Optional.h - Simple variant for passing optional values ---*- C++ -*-=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file provides Optional, a template class modeled in the spirit of
|
||||
// OCaml's 'opt' variant. The idea is to strongly type whether or not
|
||||
// a value can be optional.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_OPTIONAL_H
|
||||
#define LLVM_ADT_OPTIONAL_H
|
||||
|
||||
#include "llvm/None.h"
|
||||
#include "llvm/AlignOf.h"
|
||||
#include "llvm/Compiler.h"
|
||||
#include <cassert>
|
||||
#include <new>
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
template<typename T>
|
||||
class Optional {
|
||||
AlignedCharArrayUnion<T> storage;
|
||||
bool hasVal;
|
||||
public:
|
||||
typedef T value_type;
|
||||
|
||||
Optional(NoneType) : hasVal(false) {}
|
||||
explicit Optional() : hasVal(false) {}
|
||||
Optional(const T &y) : hasVal(true) {
|
||||
new (storage.buffer) T(y);
|
||||
}
|
||||
Optional(const Optional &O) : hasVal(O.hasVal) {
|
||||
if (hasVal)
|
||||
new (storage.buffer) T(*O);
|
||||
}
|
||||
|
||||
Optional(T &&y) : hasVal(true) {
|
||||
new (storage.buffer) T(std::forward<T>(y));
|
||||
}
|
||||
Optional(Optional<T> &&O) : hasVal(O) {
|
||||
if (O) {
|
||||
new (storage.buffer) T(std::move(*O));
|
||||
O.reset();
|
||||
}
|
||||
}
|
||||
Optional &operator=(T &&y) {
|
||||
if (hasVal)
|
||||
**this = std::move(y);
|
||||
else {
|
||||
new (storage.buffer) T(std::move(y));
|
||||
hasVal = true;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
Optional &operator=(Optional &&O) {
|
||||
if (!O)
|
||||
reset();
|
||||
else {
|
||||
*this = std::move(*O);
|
||||
O.reset();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Create a new object by constructing it in place with the given arguments.
|
||||
template<typename ...ArgTypes>
|
||||
void emplace(ArgTypes &&...Args) {
|
||||
reset();
|
||||
hasVal = true;
|
||||
new (storage.buffer) T(std::forward<ArgTypes>(Args)...);
|
||||
}
|
||||
|
||||
static inline Optional create(const T* y) {
|
||||
return y ? Optional(*y) : Optional();
|
||||
}
|
||||
|
||||
// FIXME: these assignments (& the equivalent const T&/const Optional& ctors)
|
||||
// could be made more efficient by passing by value, possibly unifying them
|
||||
// with the rvalue versions above - but this could place a different set of
|
||||
// requirements (notably: the existence of a default ctor) when implemented
|
||||
// in that way. Careful SFINAE to avoid such pitfalls would be required.
|
||||
Optional &operator=(const T &y) {
|
||||
if (hasVal)
|
||||
**this = y;
|
||||
else {
|
||||
new (storage.buffer) T(y);
|
||||
hasVal = true;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Optional &operator=(const Optional &O) {
|
||||
if (!O)
|
||||
reset();
|
||||
else
|
||||
*this = *O;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
if (hasVal) {
|
||||
(**this).~T();
|
||||
hasVal = false;
|
||||
}
|
||||
}
|
||||
|
||||
~Optional() {
|
||||
reset();
|
||||
}
|
||||
|
||||
const T* getPointer() const { assert(hasVal); return reinterpret_cast<const T*>(storage.buffer); }
|
||||
T* getPointer() { assert(hasVal); return reinterpret_cast<T*>(storage.buffer); }
|
||||
const T& getValue() const LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); }
|
||||
T& getValue() LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); }
|
||||
|
||||
explicit operator bool() const { return hasVal; }
|
||||
bool hasValue() const { return hasVal; }
|
||||
const T* operator->() const { return getPointer(); }
|
||||
T* operator->() { return getPointer(); }
|
||||
const T& operator*() const LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); }
|
||||
T& operator*() LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); }
|
||||
|
||||
template <typename U>
|
||||
LLVM_CONSTEXPR T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION {
|
||||
return hasValue() ? getValue() : std::forward<U>(value);
|
||||
}
|
||||
|
||||
#if LLVM_HAS_RVALUE_REFERENCE_THIS
|
||||
T&& getValue() && { assert(hasVal); return std::move(*getPointer()); }
|
||||
T&& operator*() && { assert(hasVal); return std::move(*getPointer()); }
|
||||
|
||||
template <typename U>
|
||||
T getValueOr(U &&value) && {
|
||||
return hasValue() ? std::move(getValue()) : std::forward<U>(value);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename T> struct isPodLike;
|
||||
template <typename T> struct isPodLike<Optional<T> > {
|
||||
// An Optional<T> is pod-like if T is.
|
||||
static const bool value = isPodLike<T>::value;
|
||||
};
|
||||
|
||||
/// \brief Poison comparison between two \c Optional objects. Clients needs to
|
||||
/// explicitly compare the underlying values and account for empty \c Optional
|
||||
/// objects.
|
||||
///
|
||||
/// This routine will never be defined. It returns \c void to help diagnose
|
||||
/// errors at compile time.
|
||||
template<typename T, typename U>
|
||||
void operator==(const Optional<T> &X, const Optional<U> &Y);
|
||||
|
||||
template<typename T>
|
||||
bool operator==(const Optional<T> &X, NoneType) {
|
||||
return !X.hasValue();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool operator==(NoneType, const Optional<T> &X) {
|
||||
return X == None;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool operator!=(const Optional<T> &X, NoneType) {
|
||||
return !(X == None);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool operator!=(NoneType, const Optional<T> &X) {
|
||||
return X != None;
|
||||
}
|
||||
/// \brief Poison comparison between two \c Optional objects. Clients needs to
|
||||
/// explicitly compare the underlying values and account for empty \c Optional
|
||||
/// objects.
|
||||
///
|
||||
/// This routine will never be defined. It returns \c void to help diagnose
|
||||
/// errors at compile time.
|
||||
template<typename T, typename U>
|
||||
void operator!=(const Optional<T> &X, const Optional<U> &Y);
|
||||
|
||||
/// \brief Poison comparison between two \c Optional objects. Clients needs to
|
||||
/// explicitly compare the underlying values and account for empty \c Optional
|
||||
/// objects.
|
||||
///
|
||||
/// This routine will never be defined. It returns \c void to help diagnose
|
||||
/// errors at compile time.
|
||||
template<typename T, typename U>
|
||||
void operator<(const Optional<T> &X, const Optional<U> &Y);
|
||||
|
||||
/// \brief Poison comparison between two \c Optional objects. Clients needs to
|
||||
/// explicitly compare the underlying values and account for empty \c Optional
|
||||
/// objects.
|
||||
///
|
||||
/// This routine will never be defined. It returns \c void to help diagnose
|
||||
/// errors at compile time.
|
||||
template<typename T, typename U>
|
||||
void operator<=(const Optional<T> &X, const Optional<U> &Y);
|
||||
|
||||
/// \brief Poison comparison between two \c Optional objects. Clients needs to
|
||||
/// explicitly compare the underlying values and account for empty \c Optional
|
||||
/// objects.
|
||||
///
|
||||
/// This routine will never be defined. It returns \c void to help diagnose
|
||||
/// errors at compile time.
|
||||
template<typename T, typename U>
|
||||
void operator>=(const Optional<T> &X, const Optional<U> &Y);
|
||||
|
||||
/// \brief Poison comparison between two \c Optional objects. Clients needs to
|
||||
/// explicitly compare the underlying values and account for empty \c Optional
|
||||
/// objects.
|
||||
///
|
||||
/// This routine will never be defined. It returns \c void to help diagnose
|
||||
/// errors at compile time.
|
||||
template<typename T, typename U>
|
||||
void operator>(const Optional<T> &X, const Optional<U> &Y);
|
||||
|
||||
} // end llvm namespace
|
||||
|
||||
#endif
|
||||
94
src/main/native/include/llvm/PointerLikeTypeTraits.h
Normal file
94
src/main/native/include/llvm/PointerLikeTypeTraits.h
Normal file
@@ -0,0 +1,94 @@
|
||||
//===- llvm/Support/PointerLikeTypeTraits.h - Pointer Traits ----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the PointerLikeTypeTraits class. This allows data
|
||||
// structures to reason about pointers and other things that are pointer sized.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_POINTERLIKETYPETRAITS_H
|
||||
#define LLVM_SUPPORT_POINTERLIKETYPETRAITS_H
|
||||
|
||||
#include "llvm/AlignOf.h"
|
||||
#include <cstdint>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// A traits type that is used to handle pointer types and things that are just
|
||||
/// wrappers for pointers as a uniform entity.
|
||||
template <typename T> class PointerLikeTypeTraits {
|
||||
// getAsVoidPointer
|
||||
// getFromVoidPointer
|
||||
// getNumLowBitsAvailable
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
/// A tiny meta function to compute the log2 of a compile time constant.
|
||||
template <size_t N>
|
||||
struct ConstantLog2
|
||||
: std::integral_constant<size_t, ConstantLog2<N / 2>::value + 1> {};
|
||||
template <> struct ConstantLog2<1> : std::integral_constant<size_t, 0> {};
|
||||
}
|
||||
|
||||
// Provide PointerLikeTypeTraits for non-cvr pointers.
|
||||
template <typename T> class PointerLikeTypeTraits<T *> {
|
||||
public:
|
||||
static inline void *getAsVoidPointer(T *P) { return P; }
|
||||
static inline T *getFromVoidPointer(void *P) { return static_cast<T *>(P); }
|
||||
|
||||
enum {
|
||||
NumLowBitsAvailable = detail::ConstantLog2<AlignOf<T>::Alignment>::value
|
||||
};
|
||||
};
|
||||
|
||||
template <> class PointerLikeTypeTraits<void *> {
|
||||
public:
|
||||
static inline void *getAsVoidPointer(void *P) { return P; }
|
||||
static inline void *getFromVoidPointer(void *P) { return P; }
|
||||
|
||||
/// Note, we assume here that void* is related to raw malloc'ed memory and
|
||||
/// that malloc returns objects at least 4-byte aligned. However, this may be
|
||||
/// wrong, or pointers may be from something other than malloc. In this case,
|
||||
/// you should specify a real typed pointer or avoid this template.
|
||||
///
|
||||
/// All clients should use assertions to do a run-time check to ensure that
|
||||
/// this is actually true.
|
||||
enum { NumLowBitsAvailable = 2 };
|
||||
};
|
||||
|
||||
// Provide PointerLikeTypeTraits for const pointers.
|
||||
template <typename T> class PointerLikeTypeTraits<const T *> {
|
||||
typedef PointerLikeTypeTraits<T *> NonConst;
|
||||
|
||||
public:
|
||||
static inline const void *getAsVoidPointer(const T *P) {
|
||||
return NonConst::getAsVoidPointer(const_cast<T *>(P));
|
||||
}
|
||||
static inline const T *getFromVoidPointer(const void *P) {
|
||||
return NonConst::getFromVoidPointer(const_cast<void *>(P));
|
||||
}
|
||||
enum { NumLowBitsAvailable = NonConst::NumLowBitsAvailable };
|
||||
};
|
||||
|
||||
// Provide PointerLikeTypeTraits for uintptr_t.
|
||||
template <> class PointerLikeTypeTraits<uintptr_t> {
|
||||
public:
|
||||
static inline void *getAsVoidPointer(uintptr_t P) {
|
||||
return reinterpret_cast<void *>(P);
|
||||
}
|
||||
static inline uintptr_t getFromVoidPointer(void *P) {
|
||||
return reinterpret_cast<uintptr_t>(P);
|
||||
}
|
||||
// No bits are available!
|
||||
enum { NumLowBitsAvailable = 0 };
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
521
src/main/native/include/llvm/STLExtras.h
Normal file
521
src/main/native/include/llvm/STLExtras.h
Normal file
@@ -0,0 +1,521 @@
|
||||
//===- llvm/ADT/STLExtras.h - Useful STL related functions ------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains some templates that are useful if you are working with the
|
||||
// STL at all.
|
||||
//
|
||||
// No library is required when using these functions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_STLEXTRAS_H
|
||||
#define LLVM_ADT_STLEXTRAS_H
|
||||
|
||||
#include <algorithm> // for std::all_of
|
||||
#include <cassert>
|
||||
#include <cstddef> // for std::size_t
|
||||
#include <cstdlib> // for qsort
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <utility> // for std::pair
|
||||
|
||||
#include "llvm/iterator_range.h"
|
||||
#include "llvm/Compiler.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Extra additions to <functional>
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
template<class Ty>
|
||||
struct identity : public std::unary_function<Ty, Ty> {
|
||||
Ty &operator()(Ty &self) const {
|
||||
return self;
|
||||
}
|
||||
const Ty &operator()(const Ty &self) const {
|
||||
return self;
|
||||
}
|
||||
};
|
||||
|
||||
template<class Ty>
|
||||
struct less_ptr : public std::binary_function<Ty, Ty, bool> {
|
||||
bool operator()(const Ty* left, const Ty* right) const {
|
||||
return *left < *right;
|
||||
}
|
||||
};
|
||||
|
||||
template<class Ty>
|
||||
struct greater_ptr : public std::binary_function<Ty, Ty, bool> {
|
||||
bool operator()(const Ty* left, const Ty* right) const {
|
||||
return *right < *left;
|
||||
}
|
||||
};
|
||||
|
||||
/// An efficient, type-erasing, non-owning reference to a callable. This is
|
||||
/// intended for use as the type of a function parameter that is not used
|
||||
/// after the function in question returns.
|
||||
///
|
||||
/// This class does not own the callable, so it is not in general safe to store
|
||||
/// a function_ref.
|
||||
template<typename Fn> class function_ref;
|
||||
|
||||
template<typename Ret, typename ...Params>
|
||||
class function_ref<Ret(Params...)> {
|
||||
Ret (*callback)(intptr_t callable, Params ...params);
|
||||
intptr_t callable;
|
||||
|
||||
template<typename Callable>
|
||||
static Ret callback_fn(intptr_t callable, Params ...params) {
|
||||
return (*reinterpret_cast<Callable*>(callable))(
|
||||
std::forward<Params>(params)...);
|
||||
}
|
||||
|
||||
public:
|
||||
template <typename Callable>
|
||||
function_ref(Callable &&callable,
|
||||
typename std::enable_if<
|
||||
!std::is_same<typename std::remove_reference<Callable>::type,
|
||||
function_ref>::value>::type * = nullptr)
|
||||
: callback(callback_fn<typename std::remove_reference<Callable>::type>),
|
||||
callable(reinterpret_cast<intptr_t>(&callable)) {}
|
||||
Ret operator()(Params ...params) const {
|
||||
return callback(callable, std::forward<Params>(params)...);
|
||||
}
|
||||
};
|
||||
|
||||
// deleter - Very very very simple method that is used to invoke operator
|
||||
// delete on something. It is used like this:
|
||||
//
|
||||
// for_each(V.begin(), B.end(), deleter<Interval>);
|
||||
//
|
||||
template <class T>
|
||||
inline void deleter(T *Ptr) {
|
||||
delete Ptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Extra additions to <iterator>
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// mapped_iterator - This is a simple iterator adapter that causes a function to
|
||||
// be dereferenced whenever operator* is invoked on the iterator.
|
||||
//
|
||||
template <class RootIt, class UnaryFunc>
|
||||
class mapped_iterator {
|
||||
RootIt current;
|
||||
UnaryFunc Fn;
|
||||
public:
|
||||
typedef typename std::iterator_traits<RootIt>::iterator_category
|
||||
iterator_category;
|
||||
typedef typename std::iterator_traits<RootIt>::difference_type
|
||||
difference_type;
|
||||
typedef typename std::result_of<
|
||||
UnaryFunc(decltype(*std::declval<RootIt>()))>
|
||||
::type value_type;
|
||||
|
||||
typedef void pointer;
|
||||
//typedef typename UnaryFunc::result_type *pointer;
|
||||
typedef void reference; // Can't modify value returned by fn
|
||||
|
||||
typedef RootIt iterator_type;
|
||||
|
||||
inline const RootIt &getCurrent() const { return current; }
|
||||
inline const UnaryFunc &getFunc() const { return Fn; }
|
||||
|
||||
inline explicit mapped_iterator(const RootIt &I, UnaryFunc F)
|
||||
: current(I), Fn(F) {}
|
||||
|
||||
inline value_type operator*() const { // All this work to do this
|
||||
return Fn(*current); // little change
|
||||
}
|
||||
|
||||
mapped_iterator &operator++() {
|
||||
++current;
|
||||
return *this;
|
||||
}
|
||||
mapped_iterator &operator--() {
|
||||
--current;
|
||||
return *this;
|
||||
}
|
||||
mapped_iterator operator++(int) {
|
||||
mapped_iterator __tmp = *this;
|
||||
++current;
|
||||
return __tmp;
|
||||
}
|
||||
mapped_iterator operator--(int) {
|
||||
mapped_iterator __tmp = *this;
|
||||
--current;
|
||||
return __tmp;
|
||||
}
|
||||
mapped_iterator operator+(difference_type n) const {
|
||||
return mapped_iterator(current + n, Fn);
|
||||
}
|
||||
mapped_iterator &operator+=(difference_type n) {
|
||||
current += n;
|
||||
return *this;
|
||||
}
|
||||
mapped_iterator operator-(difference_type n) const {
|
||||
return mapped_iterator(current - n, Fn);
|
||||
}
|
||||
mapped_iterator &operator-=(difference_type n) {
|
||||
current -= n;
|
||||
return *this;
|
||||
}
|
||||
reference operator[](difference_type n) const { return *(*this + n); }
|
||||
|
||||
bool operator!=(const mapped_iterator &X) const { return !operator==(X); }
|
||||
bool operator==(const mapped_iterator &X) const {
|
||||
return current == X.current;
|
||||
}
|
||||
bool operator<(const mapped_iterator &X) const { return current < X.current; }
|
||||
|
||||
difference_type operator-(const mapped_iterator &X) const {
|
||||
return current - X.current;
|
||||
}
|
||||
};
|
||||
|
||||
template <class Iterator, class Func>
|
||||
inline mapped_iterator<Iterator, Func>
|
||||
operator+(typename mapped_iterator<Iterator, Func>::difference_type N,
|
||||
const mapped_iterator<Iterator, Func> &X) {
|
||||
return mapped_iterator<Iterator, Func>(X.getCurrent() - N, X.getFunc());
|
||||
}
|
||||
|
||||
|
||||
// map_iterator - Provide a convenient way to create mapped_iterators, just like
|
||||
// make_pair is useful for creating pairs...
|
||||
//
|
||||
template <class ItTy, class FuncTy>
|
||||
inline mapped_iterator<ItTy, FuncTy> map_iterator(const ItTy &I, FuncTy F) {
|
||||
return mapped_iterator<ItTy, FuncTy>(I, F);
|
||||
}
|
||||
|
||||
/// \brief Metafunction to determine if type T has a member called rbegin().
|
||||
template <typename T> struct has_rbegin {
|
||||
template <typename U> static char(&f(const U &, decltype(&U::rbegin)))[1];
|
||||
static char(&f(...))[2];
|
||||
const static bool value = sizeof(f(std::declval<T>(), nullptr)) == 1;
|
||||
};
|
||||
|
||||
// Returns an iterator_range over the given container which iterates in reverse.
|
||||
// Note that the container must have rbegin()/rend() methods for this to work.
|
||||
template <typename ContainerTy>
|
||||
auto reverse(ContainerTy &&C,
|
||||
typename std::enable_if<has_rbegin<ContainerTy>::value>::type * =
|
||||
nullptr) -> decltype(make_range(C.rbegin(), C.rend())) {
|
||||
return make_range(C.rbegin(), C.rend());
|
||||
}
|
||||
|
||||
// Returns a std::reverse_iterator wrapped around the given iterator.
|
||||
template <typename IteratorTy>
|
||||
std::reverse_iterator<IteratorTy> make_reverse_iterator(IteratorTy It) {
|
||||
return std::reverse_iterator<IteratorTy>(It);
|
||||
}
|
||||
|
||||
// Returns an iterator_range over the given container which iterates in reverse.
|
||||
// Note that the container must have begin()/end() methods which return
|
||||
// bidirectional iterators for this to work.
|
||||
template <typename ContainerTy>
|
||||
auto reverse(
|
||||
ContainerTy &&C,
|
||||
typename std::enable_if<!has_rbegin<ContainerTy>::value>::type * = nullptr)
|
||||
-> decltype(make_range(llvm::make_reverse_iterator(std::end(C)),
|
||||
llvm::make_reverse_iterator(std::begin(C)))) {
|
||||
return make_range(llvm::make_reverse_iterator(std::end(C)),
|
||||
llvm::make_reverse_iterator(std::begin(C)));
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Extra additions to <utility>
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// \brief Function object to check whether the first component of a std::pair
|
||||
/// compares less than the first component of another std::pair.
|
||||
struct less_first {
|
||||
template <typename T> bool operator()(const T &lhs, const T &rhs) const {
|
||||
return lhs.first < rhs.first;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Function object to check whether the second component of a std::pair
|
||||
/// compares less than the second component of another std::pair.
|
||||
struct less_second {
|
||||
template <typename T> bool operator()(const T &lhs, const T &rhs) const {
|
||||
return lhs.second < rhs.second;
|
||||
}
|
||||
};
|
||||
|
||||
// A subset of N3658. More stuff can be added as-needed.
|
||||
|
||||
/// \brief Represents a compile-time sequence of integers.
|
||||
template <class T, T... I> struct integer_sequence {
|
||||
typedef T value_type;
|
||||
|
||||
static LLVM_CONSTEXPR size_t size() { return sizeof...(I); }
|
||||
};
|
||||
|
||||
/// \brief Alias for the common case of a sequence of size_ts.
|
||||
template <size_t... I>
|
||||
struct index_sequence : integer_sequence<std::size_t, I...> {};
|
||||
|
||||
template <std::size_t N, std::size_t... I>
|
||||
struct build_index_impl : build_index_impl<N - 1, N - 1, I...> {};
|
||||
template <std::size_t... I>
|
||||
struct build_index_impl<0, I...> : index_sequence<I...> {};
|
||||
|
||||
/// \brief Creates a compile-time integer sequence for a parameter pack.
|
||||
template <class... Ts>
|
||||
struct index_sequence_for : build_index_impl<sizeof...(Ts)> {};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Extra additions for arrays
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Find the length of an array.
|
||||
template <class T, std::size_t N>
|
||||
LLVM_CONSTEXPR inline size_t array_lengthof(T (&)[N]) {
|
||||
return N;
|
||||
}
|
||||
|
||||
/// Adapt std::less<T> for array_pod_sort.
|
||||
template<typename T>
|
||||
inline int array_pod_sort_comparator(const void *P1, const void *P2) {
|
||||
if (std::less<T>()(*reinterpret_cast<const T*>(P1),
|
||||
*reinterpret_cast<const T*>(P2)))
|
||||
return -1;
|
||||
if (std::less<T>()(*reinterpret_cast<const T*>(P2),
|
||||
*reinterpret_cast<const T*>(P1)))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// get_array_pod_sort_comparator - This is an internal helper function used to
|
||||
/// get type deduction of T right.
|
||||
template<typename T>
|
||||
inline int (*get_array_pod_sort_comparator(const T &))
|
||||
(const void*, const void*) {
|
||||
return array_pod_sort_comparator<T>;
|
||||
}
|
||||
|
||||
|
||||
/// array_pod_sort - This sorts an array with the specified start and end
|
||||
/// extent. This is just like std::sort, except that it calls qsort instead of
|
||||
/// using an inlined template. qsort is slightly slower than std::sort, but
|
||||
/// most sorts are not performance critical in LLVM and std::sort has to be
|
||||
/// template instantiated for each type, leading to significant measured code
|
||||
/// bloat. This function should generally be used instead of std::sort where
|
||||
/// possible.
|
||||
///
|
||||
/// This function assumes that you have simple POD-like types that can be
|
||||
/// compared with std::less and can be moved with memcpy. If this isn't true,
|
||||
/// you should use std::sort.
|
||||
///
|
||||
/// NOTE: If qsort_r were portable, we could allow a custom comparator and
|
||||
/// default to std::less.
|
||||
template<class IteratorTy>
|
||||
inline void array_pod_sort(IteratorTy Start, IteratorTy End) {
|
||||
// Don't inefficiently call qsort with one element or trigger undefined
|
||||
// behavior with an empty sequence.
|
||||
auto NElts = End - Start;
|
||||
if (NElts <= 1) return;
|
||||
qsort(&*Start, NElts, sizeof(*Start), get_array_pod_sort_comparator(*Start));
|
||||
}
|
||||
|
||||
template <class IteratorTy>
|
||||
inline void array_pod_sort(
|
||||
IteratorTy Start, IteratorTy End,
|
||||
int (*Compare)(
|
||||
const typename std::iterator_traits<IteratorTy>::value_type *,
|
||||
const typename std::iterator_traits<IteratorTy>::value_type *)) {
|
||||
// Don't inefficiently call qsort with one element or trigger undefined
|
||||
// behavior with an empty sequence.
|
||||
auto NElts = End - Start;
|
||||
if (NElts <= 1) return;
|
||||
qsort(&*Start, NElts, sizeof(*Start),
|
||||
reinterpret_cast<int (*)(const void *, const void *)>(Compare));
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Extra additions to <algorithm>
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// For a container of pointers, deletes the pointers and then clears the
|
||||
/// container.
|
||||
template<typename Container>
|
||||
void DeleteContainerPointers(Container &C) {
|
||||
for (typename Container::iterator I = C.begin(), E = C.end(); I != E; ++I)
|
||||
delete *I;
|
||||
C.clear();
|
||||
}
|
||||
|
||||
/// In a container of pairs (usually a map) whose second element is a pointer,
|
||||
/// deletes the second elements and then clears the container.
|
||||
template<typename Container>
|
||||
void DeleteContainerSeconds(Container &C) {
|
||||
for (typename Container::iterator I = C.begin(), E = C.end(); I != E; ++I)
|
||||
delete I->second;
|
||||
C.clear();
|
||||
}
|
||||
|
||||
/// Provide wrappers to std::all_of which take ranges instead of having to pass
|
||||
/// begin/end explicitly.
|
||||
template<typename R, class UnaryPredicate>
|
||||
bool all_of(R &&Range, UnaryPredicate &&P) {
|
||||
return std::all_of(Range.begin(), Range.end(),
|
||||
std::forward<UnaryPredicate>(P));
|
||||
}
|
||||
|
||||
/// Provide wrappers to std::any_of which take ranges instead of having to pass
|
||||
/// begin/end explicitly.
|
||||
template <typename R, class UnaryPredicate>
|
||||
bool any_of(R &&Range, UnaryPredicate &&P) {
|
||||
return std::any_of(Range.begin(), Range.end(),
|
||||
std::forward<UnaryPredicate>(P));
|
||||
}
|
||||
|
||||
/// Provide wrappers to std::none_of which take ranges instead of having to pass
|
||||
/// begin/end explicitly.
|
||||
template <typename R, class UnaryPredicate>
|
||||
bool none_of(R &&Range, UnaryPredicate &&P) {
|
||||
return std::none_of(Range.begin(), Range.end(),
|
||||
std::forward<UnaryPredicate>(P));
|
||||
}
|
||||
|
||||
/// Provide wrappers to std::find which take ranges instead of having to pass
|
||||
/// begin/end explicitly.
|
||||
template<typename R, class T>
|
||||
auto find(R &&Range, const T &val) -> decltype(Range.begin()) {
|
||||
return std::find(Range.begin(), Range.end(), val);
|
||||
}
|
||||
|
||||
/// Provide wrappers to std::find_if which take ranges instead of having to pass
|
||||
/// begin/end explicitly.
|
||||
template <typename R, class T>
|
||||
auto find_if(R &&Range, const T &Pred) -> decltype(Range.begin()) {
|
||||
return std::find_if(Range.begin(), Range.end(), Pred);
|
||||
}
|
||||
|
||||
/// Provide wrappers to std::remove_if which take ranges instead of having to
|
||||
/// pass begin/end explicitly.
|
||||
template<typename R, class UnaryPredicate>
|
||||
auto remove_if(R &&Range, UnaryPredicate &&P) -> decltype(Range.begin()) {
|
||||
return std::remove_if(Range.begin(), Range.end(), P);
|
||||
}
|
||||
|
||||
/// Wrapper function around std::find to detect if an element exists
|
||||
/// in a container.
|
||||
template <typename R, typename E>
|
||||
bool is_contained(R &&Range, const E &Element) {
|
||||
return std::find(Range.begin(), Range.end(), Element) != Range.end();
|
||||
}
|
||||
|
||||
/// Wrapper function around std::count_if to count the number of times an
|
||||
/// element satisfying a given predicate occurs in a range.
|
||||
template <typename R, typename UnaryPredicate>
|
||||
auto count_if(R &&Range, UnaryPredicate &&P)
|
||||
-> typename std::iterator_traits<decltype(Range.begin())>::difference_type {
|
||||
return std::count_if(Range.begin(), Range.end(), P);
|
||||
}
|
||||
|
||||
/// Wrapper function around std::transform to apply a function to a range and
|
||||
/// store the result elsewhere.
|
||||
template <typename R, class OutputIt, typename UnaryPredicate>
|
||||
OutputIt transform(R &&Range, OutputIt d_first, UnaryPredicate &&P) {
|
||||
return std::transform(Range.begin(), Range.end(), d_first,
|
||||
std::forward<UnaryPredicate>(P));
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Extra additions to <memory>
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Implement make_unique according to N3656.
|
||||
|
||||
/// \brief Constructs a `new T()` with the given args and returns a
|
||||
/// `unique_ptr<T>` which owns the object.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// auto p = make_unique<int>();
|
||||
/// auto p = make_unique<std::tuple<int, int>>(0, 1);
|
||||
template <class T, class... Args>
|
||||
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
|
||||
make_unique(Args &&... args) {
|
||||
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
/// \brief Constructs a `new T[n]` with the given args and returns a
|
||||
/// `unique_ptr<T[]>` which owns the object.
|
||||
///
|
||||
/// \param n size of the new array.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// auto p = make_unique<int[]>(2); // value-initializes the array with 0's.
|
||||
template <class T>
|
||||
typename std::enable_if<std::is_array<T>::value && std::extent<T>::value == 0,
|
||||
std::unique_ptr<T>>::type
|
||||
make_unique(size_t n) {
|
||||
return std::unique_ptr<T>(new typename std::remove_extent<T>::type[n]());
|
||||
}
|
||||
|
||||
/// This function isn't used and is only here to provide better compile errors.
|
||||
template <class T, class... Args>
|
||||
typename std::enable_if<std::extent<T>::value != 0>::type
|
||||
make_unique(Args &&...) = delete;
|
||||
|
||||
struct FreeDeleter {
|
||||
void operator()(void* v) {
|
||||
::free(v);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename First, typename Second>
|
||||
struct pair_hash {
|
||||
size_t operator()(const std::pair<First, Second> &P) const {
|
||||
return std::hash<First>()(P.first) * 31 + std::hash<Second>()(P.second);
|
||||
}
|
||||
};
|
||||
|
||||
/// A functor like C++14's std::less<void> in its absence.
|
||||
struct less {
|
||||
template <typename A, typename B> bool operator()(A &&a, B &&b) const {
|
||||
return std::forward<A>(a) < std::forward<B>(b);
|
||||
}
|
||||
};
|
||||
|
||||
/// A functor like C++14's std::equal<void> in its absence.
|
||||
struct equal {
|
||||
template <typename A, typename B> bool operator()(A &&a, B &&b) const {
|
||||
return std::forward<A>(a) == std::forward<B>(b);
|
||||
}
|
||||
};
|
||||
|
||||
/// Binary functor that adapts to any other binary functor after dereferencing
|
||||
/// operands.
|
||||
template <typename T> struct deref {
|
||||
T func;
|
||||
// Could be further improved to cope with non-derivable functors and
|
||||
// non-binary functors (should be a variadic template member function
|
||||
// operator()).
|
||||
template <typename A, typename B>
|
||||
auto operator()(A &lhs, B &rhs) const -> decltype(func(*lhs, *rhs)) {
|
||||
assert(lhs);
|
||||
assert(rhs);
|
||||
return func(*lhs, *rhs);
|
||||
}
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
||||
406
src/main/native/include/llvm/SmallPtrSet.h
Normal file
406
src/main/native/include/llvm/SmallPtrSet.h
Normal file
@@ -0,0 +1,406 @@
|
||||
//===- llvm/ADT/SmallPtrSet.h - 'Normally small' pointer set ----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the SmallPtrSet class. See the doxygen comment for
|
||||
// SmallPtrSetImplBase for more details on the algorithm used.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_SMALLPTRSET_H
|
||||
#define LLVM_ADT_SMALLPTRSET_H
|
||||
|
||||
#include "llvm/Compiler.h"
|
||||
#include "llvm/PointerLikeTypeTraits.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class SmallPtrSetIteratorImpl;
|
||||
|
||||
/// SmallPtrSetImplBase - This is the common code shared among all the
|
||||
/// SmallPtrSet<>'s, which is almost everything. SmallPtrSet has two modes, one
|
||||
/// for small and one for large sets.
|
||||
///
|
||||
/// Small sets use an array of pointers allocated in the SmallPtrSet object,
|
||||
/// which is treated as a simple array of pointers. When a pointer is added to
|
||||
/// the set, the array is scanned to see if the element already exists, if not
|
||||
/// the element is 'pushed back' onto the array. If we run out of space in the
|
||||
/// array, we grow into the 'large set' case. SmallSet should be used when the
|
||||
/// sets are often small. In this case, no memory allocation is used, and only
|
||||
/// light-weight and cache-efficient scanning is used.
|
||||
///
|
||||
/// Large sets use a classic exponentially-probed hash table. Empty buckets are
|
||||
/// represented with an illegal pointer value (-1) to allow null pointers to be
|
||||
/// inserted. Tombstones are represented with another illegal pointer value
|
||||
/// (-2), to allow deletion. The hash table is resized when the table is 3/4 or
|
||||
/// more. When this happens, the table is doubled in size.
|
||||
///
|
||||
class SmallPtrSetImplBase {
|
||||
friend class SmallPtrSetIteratorImpl;
|
||||
|
||||
protected:
|
||||
/// SmallArray - Points to a fixed size set of buckets, used in 'small mode'.
|
||||
const void **SmallArray;
|
||||
/// CurArray - This is the current set of buckets. If equal to SmallArray,
|
||||
/// then the set is in 'small mode'.
|
||||
const void **CurArray;
|
||||
/// CurArraySize - The allocated size of CurArray, always a power of two.
|
||||
unsigned CurArraySize;
|
||||
|
||||
/// Number of elements in CurArray that contain a value or are a tombstone.
|
||||
/// If small, all these elements are at the beginning of CurArray and the rest
|
||||
/// is uninitialized.
|
||||
unsigned NumNonEmpty;
|
||||
/// Number of tombstones in CurArray.
|
||||
unsigned NumTombstones;
|
||||
|
||||
// Helpers to copy and move construct a SmallPtrSet.
|
||||
SmallPtrSetImplBase(const void **SmallStorage,
|
||||
const SmallPtrSetImplBase &that);
|
||||
SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize,
|
||||
SmallPtrSetImplBase &&that);
|
||||
explicit SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize)
|
||||
: SmallArray(SmallStorage), CurArray(SmallStorage),
|
||||
CurArraySize(SmallSize), NumNonEmpty(0), NumTombstones(0) {
|
||||
assert(SmallSize && (SmallSize & (SmallSize-1)) == 0 &&
|
||||
"Initial size must be a power of two!");
|
||||
}
|
||||
~SmallPtrSetImplBase() {
|
||||
if (!isSmall())
|
||||
free(CurArray);
|
||||
}
|
||||
|
||||
public:
|
||||
typedef unsigned size_type;
|
||||
bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const { return size() == 0; }
|
||||
size_type size() const { return NumNonEmpty - NumTombstones; }
|
||||
|
||||
void clear() {
|
||||
// If the capacity of the array is huge, and the # elements used is small,
|
||||
// shrink the array.
|
||||
if (!isSmall()) {
|
||||
if (size() * 4 < CurArraySize && CurArraySize > 32)
|
||||
return shrink_and_clear();
|
||||
// Fill the array with empty markers.
|
||||
memset(CurArray, -1, CurArraySize * sizeof(void *));
|
||||
}
|
||||
|
||||
NumNonEmpty = 0;
|
||||
NumTombstones = 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
static void *getTombstoneMarker() { return reinterpret_cast<void*>(-2); }
|
||||
static void *getEmptyMarker() {
|
||||
// Note that -1 is chosen to make clear() efficiently implementable with
|
||||
// memset and because it's not a valid pointer value.
|
||||
return reinterpret_cast<void*>(-1);
|
||||
}
|
||||
|
||||
const void **EndPointer() const {
|
||||
return isSmall() ? CurArray + NumNonEmpty : CurArray + CurArraySize;
|
||||
}
|
||||
|
||||
/// insert_imp - This returns true if the pointer was new to the set, false if
|
||||
/// it was already in the set. This is hidden from the client so that the
|
||||
/// derived class can check that the right type of pointer is passed in.
|
||||
std::pair<const void *const *, bool> insert_imp(const void *Ptr) {
|
||||
if (isSmall()) {
|
||||
// Check to see if it is already in the set.
|
||||
const void **LastTombstone = nullptr;
|
||||
for (const void **APtr = SmallArray, **E = SmallArray + NumNonEmpty;
|
||||
APtr != E; ++APtr) {
|
||||
const void *Value = *APtr;
|
||||
if (Value == Ptr)
|
||||
return std::make_pair(APtr, false);
|
||||
if (Value == getTombstoneMarker())
|
||||
LastTombstone = APtr;
|
||||
}
|
||||
|
||||
// Did we find any tombstone marker?
|
||||
if (LastTombstone != nullptr) {
|
||||
*LastTombstone = Ptr;
|
||||
--NumTombstones;
|
||||
return std::make_pair(LastTombstone, true);
|
||||
}
|
||||
|
||||
// Nope, there isn't. If we stay small, just 'pushback' now.
|
||||
if (NumNonEmpty < CurArraySize) {
|
||||
SmallArray[NumNonEmpty++] = Ptr;
|
||||
return std::make_pair(SmallArray + (NumNonEmpty - 1), true);
|
||||
}
|
||||
// Otherwise, hit the big set case, which will call grow.
|
||||
}
|
||||
return insert_imp_big(Ptr);
|
||||
}
|
||||
|
||||
/// erase_imp - If the set contains the specified pointer, remove it and
|
||||
/// return true, otherwise return false. This is hidden from the client so
|
||||
/// that the derived class can check that the right type of pointer is passed
|
||||
/// in.
|
||||
bool erase_imp(const void * Ptr);
|
||||
|
||||
bool count_imp(const void * Ptr) const {
|
||||
if (isSmall()) {
|
||||
// Linear search for the item.
|
||||
for (const void *const *APtr = SmallArray,
|
||||
*const *E = SmallArray + NumNonEmpty; APtr != E; ++APtr)
|
||||
if (*APtr == Ptr)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Big set case.
|
||||
return *FindBucketFor(Ptr) == Ptr;
|
||||
}
|
||||
|
||||
private:
|
||||
bool isSmall() const { return CurArray == SmallArray; }
|
||||
|
||||
std::pair<const void *const *, bool> insert_imp_big(const void *Ptr);
|
||||
|
||||
const void * const *FindBucketFor(const void *Ptr) const;
|
||||
void shrink_and_clear();
|
||||
|
||||
/// Grow - Allocate a larger backing store for the buckets and move it over.
|
||||
void Grow(unsigned NewSize);
|
||||
|
||||
void operator=(const SmallPtrSetImplBase &RHS) = delete;
|
||||
|
||||
protected:
|
||||
/// swap - Swaps the elements of two sets.
|
||||
/// Note: This method assumes that both sets have the same small size.
|
||||
void swap(SmallPtrSetImplBase &RHS);
|
||||
|
||||
void CopyFrom(const SmallPtrSetImplBase &RHS);
|
||||
void MoveFrom(unsigned SmallSize, SmallPtrSetImplBase &&RHS);
|
||||
|
||||
private:
|
||||
/// Code shared by MoveFrom() and move constructor.
|
||||
void MoveHelper(unsigned SmallSize, SmallPtrSetImplBase &&RHS);
|
||||
/// Code shared by CopyFrom() and copy constructor.
|
||||
void CopyHelper(const SmallPtrSetImplBase &RHS);
|
||||
};
|
||||
|
||||
/// SmallPtrSetIteratorImpl - This is the common base class shared between all
|
||||
/// instances of SmallPtrSetIterator.
|
||||
class SmallPtrSetIteratorImpl {
|
||||
protected:
|
||||
const void *const *Bucket;
|
||||
const void *const *End;
|
||||
|
||||
public:
|
||||
explicit SmallPtrSetIteratorImpl(const void *const *BP, const void*const *E)
|
||||
: Bucket(BP), End(E) {
|
||||
AdvanceIfNotValid();
|
||||
}
|
||||
|
||||
bool operator==(const SmallPtrSetIteratorImpl &RHS) const {
|
||||
return Bucket == RHS.Bucket;
|
||||
}
|
||||
bool operator!=(const SmallPtrSetIteratorImpl &RHS) const {
|
||||
return Bucket != RHS.Bucket;
|
||||
}
|
||||
|
||||
protected:
|
||||
/// AdvanceIfNotValid - If the current bucket isn't valid, advance to a bucket
|
||||
/// that is. This is guaranteed to stop because the end() bucket is marked
|
||||
/// valid.
|
||||
void AdvanceIfNotValid() {
|
||||
assert(Bucket <= End);
|
||||
while (Bucket != End &&
|
||||
(*Bucket == SmallPtrSetImplBase::getEmptyMarker() ||
|
||||
*Bucket == SmallPtrSetImplBase::getTombstoneMarker()))
|
||||
++Bucket;
|
||||
}
|
||||
};
|
||||
|
||||
/// SmallPtrSetIterator - This implements a const_iterator for SmallPtrSet.
|
||||
template<typename PtrTy>
|
||||
class SmallPtrSetIterator : public SmallPtrSetIteratorImpl {
|
||||
typedef PointerLikeTypeTraits<PtrTy> PtrTraits;
|
||||
|
||||
public:
|
||||
typedef PtrTy value_type;
|
||||
typedef PtrTy reference;
|
||||
typedef PtrTy pointer;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
explicit SmallPtrSetIterator(const void *const *BP, const void *const *E)
|
||||
: SmallPtrSetIteratorImpl(BP, E) {}
|
||||
|
||||
// Most methods provided by baseclass.
|
||||
|
||||
const PtrTy operator*() const {
|
||||
assert(Bucket < End);
|
||||
return PtrTraits::getFromVoidPointer(const_cast<void*>(*Bucket));
|
||||
}
|
||||
|
||||
inline SmallPtrSetIterator& operator++() { // Preincrement
|
||||
++Bucket;
|
||||
AdvanceIfNotValid();
|
||||
return *this;
|
||||
}
|
||||
|
||||
SmallPtrSetIterator operator++(int) { // Postincrement
|
||||
SmallPtrSetIterator tmp = *this; ++*this; return tmp;
|
||||
}
|
||||
};
|
||||
|
||||
/// RoundUpToPowerOfTwo - This is a helper template that rounds N up to the next
|
||||
/// power of two (which means N itself if N is already a power of two).
|
||||
template<unsigned N>
|
||||
struct RoundUpToPowerOfTwo;
|
||||
|
||||
/// RoundUpToPowerOfTwoH - If N is not a power of two, increase it. This is a
|
||||
/// helper template used to implement RoundUpToPowerOfTwo.
|
||||
template<unsigned N, bool isPowerTwo>
|
||||
struct RoundUpToPowerOfTwoH {
|
||||
enum { Val = N };
|
||||
};
|
||||
template<unsigned N>
|
||||
struct RoundUpToPowerOfTwoH<N, false> {
|
||||
enum {
|
||||
// We could just use NextVal = N+1, but this converges faster. N|(N-1) sets
|
||||
// the right-most zero bits to one all at once, e.g. 0b0011000 -> 0b0011111.
|
||||
Val = RoundUpToPowerOfTwo<(N|(N-1)) + 1>::Val
|
||||
};
|
||||
};
|
||||
|
||||
template<unsigned N>
|
||||
struct RoundUpToPowerOfTwo {
|
||||
enum { Val = RoundUpToPowerOfTwoH<N, (N&(N-1)) == 0>::Val };
|
||||
};
|
||||
|
||||
/// \brief A templated base class for \c SmallPtrSet which provides the
|
||||
/// typesafe interface that is common across all small sizes.
|
||||
///
|
||||
/// This is particularly useful for passing around between interface boundaries
|
||||
/// to avoid encoding a particular small size in the interface boundary.
|
||||
template <typename PtrType>
|
||||
class SmallPtrSetImpl : public SmallPtrSetImplBase {
|
||||
typedef PointerLikeTypeTraits<PtrType> PtrTraits;
|
||||
|
||||
SmallPtrSetImpl(const SmallPtrSetImpl &) = delete;
|
||||
|
||||
protected:
|
||||
// Constructors that forward to the base.
|
||||
SmallPtrSetImpl(const void **SmallStorage, const SmallPtrSetImpl &that)
|
||||
: SmallPtrSetImplBase(SmallStorage, that) {}
|
||||
SmallPtrSetImpl(const void **SmallStorage, unsigned SmallSize,
|
||||
SmallPtrSetImpl &&that)
|
||||
: SmallPtrSetImplBase(SmallStorage, SmallSize, std::move(that)) {}
|
||||
explicit SmallPtrSetImpl(const void **SmallStorage, unsigned SmallSize)
|
||||
: SmallPtrSetImplBase(SmallStorage, SmallSize) {}
|
||||
|
||||
public:
|
||||
typedef SmallPtrSetIterator<PtrType> iterator;
|
||||
typedef SmallPtrSetIterator<PtrType> const_iterator;
|
||||
|
||||
/// Inserts Ptr if and only if there is no element in the container equal to
|
||||
/// Ptr. The bool component of the returned pair is true if and only if the
|
||||
/// insertion takes place, and the iterator component of the pair points to
|
||||
/// the element equal to Ptr.
|
||||
std::pair<iterator, bool> insert(PtrType Ptr) {
|
||||
auto p = insert_imp(PtrTraits::getAsVoidPointer(Ptr));
|
||||
return std::make_pair(iterator(p.first, EndPointer()), p.second);
|
||||
}
|
||||
|
||||
/// erase - If the set contains the specified pointer, remove it and return
|
||||
/// true, otherwise return false.
|
||||
bool erase(PtrType Ptr) {
|
||||
return erase_imp(PtrTraits::getAsVoidPointer(Ptr));
|
||||
}
|
||||
|
||||
/// count - Return 1 if the specified pointer is in the set, 0 otherwise.
|
||||
size_type count(PtrType Ptr) const {
|
||||
return count_imp(PtrTraits::getAsVoidPointer(Ptr)) ? 1 : 0;
|
||||
}
|
||||
|
||||
template <typename IterT>
|
||||
void insert(IterT I, IterT E) {
|
||||
for (; I != E; ++I)
|
||||
insert(*I);
|
||||
}
|
||||
|
||||
inline iterator begin() const {
|
||||
return iterator(CurArray, EndPointer());
|
||||
}
|
||||
inline iterator end() const {
|
||||
const void *const *End = EndPointer();
|
||||
return iterator(End, End);
|
||||
}
|
||||
};
|
||||
|
||||
/// SmallPtrSet - This class implements a set which is optimized for holding
|
||||
/// SmallSize or less elements. This internally rounds up SmallSize to the next
|
||||
/// power of two if it is not already a power of two. See the comments above
|
||||
/// SmallPtrSetImplBase for details of the algorithm.
|
||||
template<class PtrType, unsigned SmallSize>
|
||||
class SmallPtrSet : public SmallPtrSetImpl<PtrType> {
|
||||
// In small mode SmallPtrSet uses linear search for the elements, so it is
|
||||
// not a good idea to choose this value too high. You may consider using a
|
||||
// DenseSet<> instead if you expect many elements in the set.
|
||||
static_assert(SmallSize <= 32, "SmallSize should be small");
|
||||
|
||||
typedef SmallPtrSetImpl<PtrType> BaseT;
|
||||
|
||||
// Make sure that SmallSize is a power of two, round up if not.
|
||||
enum { SmallSizePowTwo = RoundUpToPowerOfTwo<SmallSize>::Val };
|
||||
/// SmallStorage - Fixed size storage used in 'small mode'.
|
||||
const void *SmallStorage[SmallSizePowTwo];
|
||||
|
||||
public:
|
||||
SmallPtrSet() : BaseT(SmallStorage, SmallSizePowTwo) {}
|
||||
SmallPtrSet(const SmallPtrSet &that) : BaseT(SmallStorage, that) {}
|
||||
SmallPtrSet(SmallPtrSet &&that)
|
||||
: BaseT(SmallStorage, SmallSizePowTwo, std::move(that)) {}
|
||||
|
||||
template<typename It>
|
||||
SmallPtrSet(It I, It E) : BaseT(SmallStorage, SmallSizePowTwo) {
|
||||
this->insert(I, E);
|
||||
}
|
||||
|
||||
SmallPtrSet<PtrType, SmallSize> &
|
||||
operator=(const SmallPtrSet<PtrType, SmallSize> &RHS) {
|
||||
if (&RHS != this)
|
||||
this->CopyFrom(RHS);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SmallPtrSet<PtrType, SmallSize>&
|
||||
operator=(SmallPtrSet<PtrType, SmallSize> &&RHS) {
|
||||
if (&RHS != this)
|
||||
this->MoveFrom(SmallSizePowTwo, std::move(RHS));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// swap - Swaps the elements of two sets.
|
||||
void swap(SmallPtrSet<PtrType, SmallSize> &RHS) {
|
||||
SmallPtrSetImplBase::swap(RHS);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace std {
|
||||
/// Implement std::swap in terms of SmallPtrSet swap.
|
||||
template<class T, unsigned N>
|
||||
inline void swap(llvm::SmallPtrSet<T, N> &LHS, llvm::SmallPtrSet<T, N> &RHS) {
|
||||
LHS.swap(RHS);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
136
src/main/native/include/llvm/SmallSet.h
Normal file
136
src/main/native/include/llvm/SmallSet.h
Normal file
@@ -0,0 +1,136 @@
|
||||
//===- llvm/ADT/SmallSet.h - 'Normally small' sets --------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the SmallSet class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_SMALLSET_H
|
||||
#define LLVM_ADT_SMALLSET_H
|
||||
|
||||
#include "llvm/None.h"
|
||||
#include "llvm/SmallPtrSet.h"
|
||||
#include "llvm/SmallVector.h"
|
||||
#include <set>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// SmallSet - This maintains a set of unique values, optimizing for the case
|
||||
/// when the set is small (less than N). In this case, the set can be
|
||||
/// maintained with no mallocs. If the set gets large, we expand to using an
|
||||
/// std::set to maintain reasonable lookup times.
|
||||
///
|
||||
/// Note that this set does not provide a way to iterate over members in the
|
||||
/// set.
|
||||
template <typename T, unsigned N, typename C = std::less<T> >
|
||||
class SmallSet {
|
||||
/// Use a SmallVector to hold the elements here (even though it will never
|
||||
/// reach its 'large' stage) to avoid calling the default ctors of elements
|
||||
/// we will never use.
|
||||
SmallVector<T, N> Vector;
|
||||
std::set<T, C> Set;
|
||||
typedef typename SmallVector<T, N>::const_iterator VIterator;
|
||||
typedef typename SmallVector<T, N>::iterator mutable_iterator;
|
||||
|
||||
// In small mode SmallPtrSet uses linear search for the elements, so it is
|
||||
// not a good idea to choose this value too high. You may consider using a
|
||||
// DenseSet<> instead if you expect many elements in the set.
|
||||
static_assert(N <= 32, "N should be small");
|
||||
|
||||
public:
|
||||
typedef size_t size_type;
|
||||
SmallSet() {}
|
||||
|
||||
bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const {
|
||||
return Vector.empty() && Set.empty();
|
||||
}
|
||||
|
||||
size_type size() const {
|
||||
return isSmall() ? Vector.size() : Set.size();
|
||||
}
|
||||
|
||||
/// count - Return 1 if the element is in the set, 0 otherwise.
|
||||
size_type count(const T &V) const {
|
||||
if (isSmall()) {
|
||||
// Since the collection is small, just do a linear search.
|
||||
return vfind(V) == Vector.end() ? 0 : 1;
|
||||
} else {
|
||||
return Set.count(V);
|
||||
}
|
||||
}
|
||||
|
||||
/// insert - Insert an element into the set if it isn't already there.
|
||||
/// Returns true if the element is inserted (it was not in the set before).
|
||||
/// The first value of the returned pair is unused and provided for
|
||||
/// partial compatibility with the standard library self-associative container
|
||||
/// concept.
|
||||
// FIXME: Add iterators that abstract over the small and large form, and then
|
||||
// return those here.
|
||||
std::pair<NoneType, bool> insert(const T &V) {
|
||||
if (!isSmall())
|
||||
return std::make_pair(None, Set.insert(V).second);
|
||||
|
||||
VIterator I = vfind(V);
|
||||
if (I != Vector.end()) // Don't reinsert if it already exists.
|
||||
return std::make_pair(None, false);
|
||||
if (Vector.size() < N) {
|
||||
Vector.push_back(V);
|
||||
return std::make_pair(None, true);
|
||||
}
|
||||
|
||||
// Otherwise, grow from vector to set.
|
||||
while (!Vector.empty()) {
|
||||
Set.insert(Vector.back());
|
||||
Vector.pop_back();
|
||||
}
|
||||
Set.insert(V);
|
||||
return std::make_pair(None, true);
|
||||
}
|
||||
|
||||
template <typename IterT>
|
||||
void insert(IterT I, IterT E) {
|
||||
for (; I != E; ++I)
|
||||
insert(*I);
|
||||
}
|
||||
|
||||
bool erase(const T &V) {
|
||||
if (!isSmall())
|
||||
return Set.erase(V);
|
||||
for (mutable_iterator I = Vector.begin(), E = Vector.end(); I != E; ++I)
|
||||
if (*I == V) {
|
||||
Vector.erase(I);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
Vector.clear();
|
||||
Set.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
bool isSmall() const { return Set.empty(); }
|
||||
|
||||
VIterator vfind(const T &V) const {
|
||||
for (VIterator I = Vector.begin(), E = Vector.end(); I != E; ++I)
|
||||
if (*I == V)
|
||||
return I;
|
||||
return Vector.end();
|
||||
}
|
||||
};
|
||||
|
||||
/// If this set is of pointer values, transparently switch over to using
|
||||
/// SmallPtrSet for performance.
|
||||
template <typename PointeeType, unsigned N>
|
||||
class SmallSet<PointeeType*, N> : public SmallPtrSet<PointeeType*, N> {};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
297
src/main/native/include/llvm/SmallString.h
Normal file
297
src/main/native/include/llvm/SmallString.h
Normal file
@@ -0,0 +1,297 @@
|
||||
//===- llvm/ADT/SmallString.h - 'Normally small' strings --------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the SmallString class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_SMALLSTRING_H
|
||||
#define LLVM_ADT_SMALLSTRING_H
|
||||
|
||||
#include "llvm/SmallVector.h"
|
||||
#include "llvm/StringRef.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// SmallString - A SmallString is just a SmallVector with methods and accessors
|
||||
/// that make it work better as a string (e.g. operator+ etc).
|
||||
template<unsigned InternalLen>
|
||||
class SmallString : public SmallVector<char, InternalLen> {
|
||||
public:
|
||||
/// Default ctor - Initialize to empty.
|
||||
SmallString() {}
|
||||
|
||||
/// Initialize from a StringRef.
|
||||
SmallString(StringRef S) : SmallVector<char, InternalLen>(S.begin(), S.end()) {}
|
||||
|
||||
/// Initialize with a range.
|
||||
template<typename ItTy>
|
||||
SmallString(ItTy S, ItTy E) : SmallVector<char, InternalLen>(S, E) {}
|
||||
|
||||
// Note that in order to add new overloads for append & assign, we have to
|
||||
// duplicate the inherited versions so as not to inadvertently hide them.
|
||||
|
||||
/// @}
|
||||
/// @name String Assignment
|
||||
/// @{
|
||||
|
||||
/// Assign from a repeated element.
|
||||
void assign(size_t NumElts, char Elt) {
|
||||
this->SmallVectorImpl<char>::assign(NumElts, Elt);
|
||||
}
|
||||
|
||||
/// Assign from an iterator pair.
|
||||
template<typename in_iter>
|
||||
void assign(in_iter S, in_iter E) {
|
||||
this->clear();
|
||||
SmallVectorImpl<char>::append(S, E);
|
||||
}
|
||||
|
||||
/// Assign from a StringRef.
|
||||
void assign(StringRef RHS) {
|
||||
this->clear();
|
||||
SmallVectorImpl<char>::append(RHS.begin(), RHS.end());
|
||||
}
|
||||
|
||||
/// Assign from a SmallVector.
|
||||
void assign(const SmallVectorImpl<char> &RHS) {
|
||||
this->clear();
|
||||
SmallVectorImpl<char>::append(RHS.begin(), RHS.end());
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name String Concatenation
|
||||
/// @{
|
||||
|
||||
/// Append from an iterator pair.
|
||||
template<typename in_iter>
|
||||
void append(in_iter S, in_iter E) {
|
||||
SmallVectorImpl<char>::append(S, E);
|
||||
}
|
||||
|
||||
void append(size_t NumInputs, char Elt) {
|
||||
SmallVectorImpl<char>::append(NumInputs, Elt);
|
||||
}
|
||||
|
||||
|
||||
/// Append from a StringRef.
|
||||
void append(StringRef RHS) {
|
||||
SmallVectorImpl<char>::append(RHS.begin(), RHS.end());
|
||||
}
|
||||
|
||||
/// Append from a SmallVector.
|
||||
void append(const SmallVectorImpl<char> &RHS) {
|
||||
SmallVectorImpl<char>::append(RHS.begin(), RHS.end());
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name String Comparison
|
||||
/// @{
|
||||
|
||||
/// Check for string equality. This is more efficient than compare() when
|
||||
/// the relative ordering of inequal strings isn't needed.
|
||||
bool equals(StringRef RHS) const {
|
||||
return str().equals(RHS);
|
||||
}
|
||||
|
||||
/// Check for string equality, ignoring case.
|
||||
bool equals_lower(StringRef RHS) const {
|
||||
return str().equals_lower(RHS);
|
||||
}
|
||||
|
||||
/// Compare two strings; the result is -1, 0, or 1 if this string is
|
||||
/// lexicographically less than, equal to, or greater than the \p RHS.
|
||||
int compare(StringRef RHS) const {
|
||||
return str().compare(RHS);
|
||||
}
|
||||
|
||||
/// compare_lower - Compare two strings, ignoring case.
|
||||
int compare_lower(StringRef RHS) const {
|
||||
return str().compare_lower(RHS);
|
||||
}
|
||||
|
||||
/// compare_numeric - Compare two strings, treating sequences of digits as
|
||||
/// numbers.
|
||||
int compare_numeric(StringRef RHS) const {
|
||||
return str().compare_numeric(RHS);
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name String Predicates
|
||||
/// @{
|
||||
|
||||
/// startswith - Check if this string starts with the given \p Prefix.
|
||||
bool startswith(StringRef Prefix) const {
|
||||
return str().startswith(Prefix);
|
||||
}
|
||||
|
||||
/// endswith - Check if this string ends with the given \p Suffix.
|
||||
bool endswith(StringRef Suffix) const {
|
||||
return str().endswith(Suffix);
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name String Searching
|
||||
/// @{
|
||||
|
||||
/// find - Search for the first character \p C in the string.
|
||||
///
|
||||
/// \return - The index of the first occurrence of \p C, or npos if not
|
||||
/// found.
|
||||
size_t find(char C, size_t From = 0) const {
|
||||
return str().find(C, From);
|
||||
}
|
||||
|
||||
/// Search for the first string \p Str in the string.
|
||||
///
|
||||
/// \returns The index of the first occurrence of \p Str, or npos if not
|
||||
/// found.
|
||||
size_t find(StringRef Str, size_t From = 0) const {
|
||||
return str().find(Str, From);
|
||||
}
|
||||
|
||||
/// Search for the last character \p C in the string.
|
||||
///
|
||||
/// \returns The index of the last occurrence of \p C, or npos if not
|
||||
/// found.
|
||||
size_t rfind(char C, size_t From = StringRef::npos) const {
|
||||
return str().rfind(C, From);
|
||||
}
|
||||
|
||||
/// Search for the last string \p Str in the string.
|
||||
///
|
||||
/// \returns The index of the last occurrence of \p Str, or npos if not
|
||||
/// found.
|
||||
size_t rfind(StringRef Str) const {
|
||||
return str().rfind(Str);
|
||||
}
|
||||
|
||||
/// Find the first character in the string that is \p C, or npos if not
|
||||
/// found. Same as find.
|
||||
size_t find_first_of(char C, size_t From = 0) const {
|
||||
return str().find_first_of(C, From);
|
||||
}
|
||||
|
||||
/// Find the first character in the string that is in \p Chars, or npos if
|
||||
/// not found.
|
||||
///
|
||||
/// Complexity: O(size() + Chars.size())
|
||||
size_t find_first_of(StringRef Chars, size_t From = 0) const {
|
||||
return str().find_first_of(Chars, From);
|
||||
}
|
||||
|
||||
/// Find the first character in the string that is not \p C or npos if not
|
||||
/// found.
|
||||
size_t find_first_not_of(char C, size_t From = 0) const {
|
||||
return str().find_first_not_of(C, From);
|
||||
}
|
||||
|
||||
/// Find the first character in the string that is not in the string
|
||||
/// \p Chars, or npos if not found.
|
||||
///
|
||||
/// Complexity: O(size() + Chars.size())
|
||||
size_t find_first_not_of(StringRef Chars, size_t From = 0) const {
|
||||
return str().find_first_not_of(Chars, From);
|
||||
}
|
||||
|
||||
/// Find the last character in the string that is \p C, or npos if not
|
||||
/// found.
|
||||
size_t find_last_of(char C, size_t From = StringRef::npos) const {
|
||||
return str().find_last_of(C, From);
|
||||
}
|
||||
|
||||
/// Find the last character in the string that is in \p C, or npos if not
|
||||
/// found.
|
||||
///
|
||||
/// Complexity: O(size() + Chars.size())
|
||||
size_t find_last_of(
|
||||
StringRef Chars, size_t From = StringRef::npos) const {
|
||||
return str().find_last_of(Chars, From);
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Helpful Algorithms
|
||||
/// @{
|
||||
|
||||
/// Return the number of occurrences of \p C in the string.
|
||||
size_t count(char C) const {
|
||||
return str().count(C);
|
||||
}
|
||||
|
||||
/// Return the number of non-overlapped occurrences of \p Str in the
|
||||
/// string.
|
||||
size_t count(StringRef Str) const {
|
||||
return str().count(Str);
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Substring Operations
|
||||
/// @{
|
||||
|
||||
/// Return a reference to the substring from [Start, Start + N).
|
||||
///
|
||||
/// \param Start The index of the starting character in the substring; if
|
||||
/// the index is npos or greater than the length of the string then the
|
||||
/// empty substring will be returned.
|
||||
///
|
||||
/// \param N The number of characters to included in the substring. If \p N
|
||||
/// exceeds the number of characters remaining in the string, the string
|
||||
/// suffix (starting with \p Start) will be returned.
|
||||
StringRef substr(size_t Start, size_t N = StringRef::npos) const {
|
||||
return str().substr(Start, N);
|
||||
}
|
||||
|
||||
/// Return a reference to the substring from [Start, End).
|
||||
///
|
||||
/// \param Start The index of the starting character in the substring; if
|
||||
/// the index is npos or greater than the length of the string then the
|
||||
/// empty substring will be returned.
|
||||
///
|
||||
/// \param End The index following the last character to include in the
|
||||
/// substring. If this is npos, or less than \p Start, or exceeds the
|
||||
/// number of characters remaining in the string, the string suffix
|
||||
/// (starting with \p Start) will be returned.
|
||||
StringRef slice(size_t Start, size_t End) const {
|
||||
return str().slice(Start, End);
|
||||
}
|
||||
|
||||
// Extra methods.
|
||||
|
||||
/// Explicit conversion to StringRef.
|
||||
StringRef str() const { return StringRef(this->begin(), this->size()); }
|
||||
|
||||
// TODO: Make this const, if it's safe...
|
||||
const char* c_str() {
|
||||
this->push_back(0);
|
||||
this->pop_back();
|
||||
return this->data();
|
||||
}
|
||||
|
||||
/// Implicit conversion to StringRef.
|
||||
operator StringRef() const { return str(); }
|
||||
|
||||
// Extra operators.
|
||||
const SmallString &operator=(StringRef RHS) {
|
||||
this->clear();
|
||||
return *this += RHS;
|
||||
}
|
||||
|
||||
SmallString &operator+=(StringRef RHS) {
|
||||
this->append(RHS.begin(), RHS.end());
|
||||
return *this;
|
||||
}
|
||||
SmallString &operator+=(char C) {
|
||||
this->push_back(C);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
920
src/main/native/include/llvm/SmallVector.h
Normal file
920
src/main/native/include/llvm/SmallVector.h
Normal file
@@ -0,0 +1,920 @@
|
||||
//===- llvm/ADT/SmallVector.h - 'Normally small' vectors --------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the SmallVector class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_SMALLVECTOR_H
|
||||
#define LLVM_ADT_SMALLVECTOR_H
|
||||
|
||||
#include "llvm/iterator_range.h"
|
||||
#include "llvm/AlignOf.h"
|
||||
#include "llvm/Compiler.h"
|
||||
#include "llvm/MathExtras.h"
|
||||
#include "llvm/type_traits.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// This is all the non-templated stuff common to all SmallVectors.
|
||||
class SmallVectorBase {
|
||||
protected:
|
||||
void *BeginX, *EndX, *CapacityX;
|
||||
|
||||
protected:
|
||||
SmallVectorBase(void *FirstEl, size_t Size)
|
||||
: BeginX(FirstEl), EndX(FirstEl), CapacityX((char*)FirstEl+Size) {}
|
||||
|
||||
/// This is an implementation of the grow() method which only works
|
||||
/// on POD-like data types and is out of line to reduce code duplication.
|
||||
void grow_pod(void *FirstEl, size_t MinSizeInBytes, size_t TSize);
|
||||
|
||||
public:
|
||||
/// This returns size()*sizeof(T).
|
||||
size_t size_in_bytes() const {
|
||||
return size_t((char*)EndX - (char*)BeginX);
|
||||
}
|
||||
|
||||
/// capacity_in_bytes - This returns capacity()*sizeof(T).
|
||||
size_t capacity_in_bytes() const {
|
||||
return size_t((char*)CapacityX - (char*)BeginX);
|
||||
}
|
||||
|
||||
bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const { return BeginX == EndX; }
|
||||
};
|
||||
|
||||
template <typename T, unsigned N> struct SmallVectorStorage;
|
||||
|
||||
/// This is the part of SmallVectorTemplateBase which does not depend on whether
|
||||
/// the type T is a POD. The extra dummy template argument is used by ArrayRef
|
||||
/// to avoid unnecessarily requiring T to be complete.
|
||||
template <typename T, typename = void>
|
||||
class SmallVectorTemplateCommon : public SmallVectorBase {
|
||||
private:
|
||||
template <typename, unsigned> friend struct SmallVectorStorage;
|
||||
|
||||
// Allocate raw space for N elements of type T. If T has a ctor or dtor, we
|
||||
// don't want it to be automatically run, so we need to represent the space as
|
||||
// something else. Use an array of char of sufficient alignment.
|
||||
typedef llvm::AlignedCharArrayUnion<T> U;
|
||||
U FirstEl;
|
||||
// Space after 'FirstEl' is clobbered, do not add any instance vars after it.
|
||||
|
||||
protected:
|
||||
SmallVectorTemplateCommon(size_t Size) : SmallVectorBase(&FirstEl, Size) {}
|
||||
|
||||
void grow_pod(size_t MinSizeInBytes, size_t TSize) {
|
||||
SmallVectorBase::grow_pod(&FirstEl, MinSizeInBytes, TSize);
|
||||
}
|
||||
|
||||
/// Return true if this is a smallvector which has not had dynamic
|
||||
/// memory allocated for it.
|
||||
bool isSmall() const {
|
||||
return BeginX == static_cast<const void*>(&FirstEl);
|
||||
}
|
||||
|
||||
/// Put this vector in a state of being small.
|
||||
void resetToSmall() {
|
||||
BeginX = EndX = CapacityX = &FirstEl;
|
||||
}
|
||||
|
||||
void setEnd(T *P) { this->EndX = P; }
|
||||
public:
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef T value_type;
|
||||
typedef T *iterator;
|
||||
typedef const T *const_iterator;
|
||||
|
||||
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
||||
typedef std::reverse_iterator<iterator> reverse_iterator;
|
||||
|
||||
typedef T &reference;
|
||||
typedef const T &const_reference;
|
||||
typedef T *pointer;
|
||||
typedef const T *const_pointer;
|
||||
|
||||
// forward iterator creation methods.
|
||||
iterator begin() { return (iterator)this->BeginX; }
|
||||
const_iterator begin() const { return (const_iterator)this->BeginX; }
|
||||
iterator end() { return (iterator)this->EndX; }
|
||||
const_iterator end() const { return (const_iterator)this->EndX; }
|
||||
protected:
|
||||
iterator capacity_ptr() { return (iterator)this->CapacityX; }
|
||||
const_iterator capacity_ptr() const { return (const_iterator)this->CapacityX;}
|
||||
public:
|
||||
|
||||
// reverse iterator creation methods.
|
||||
reverse_iterator rbegin() { return reverse_iterator(end()); }
|
||||
const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); }
|
||||
reverse_iterator rend() { return reverse_iterator(begin()); }
|
||||
const_reverse_iterator rend() const { return const_reverse_iterator(begin());}
|
||||
|
||||
size_type size() const { return end()-begin(); }
|
||||
size_type max_size() const { return size_type(-1) / sizeof(T); }
|
||||
|
||||
/// Return the total number of elements in the currently allocated buffer.
|
||||
size_t capacity() const { return capacity_ptr() - begin(); }
|
||||
|
||||
/// Return a pointer to the vector's buffer, even if empty().
|
||||
pointer data() { return pointer(begin()); }
|
||||
/// Return a pointer to the vector's buffer, even if empty().
|
||||
const_pointer data() const { return const_pointer(begin()); }
|
||||
|
||||
reference operator[](size_type idx) {
|
||||
assert(idx < size());
|
||||
return begin()[idx];
|
||||
}
|
||||
const_reference operator[](size_type idx) const {
|
||||
assert(idx < size());
|
||||
return begin()[idx];
|
||||
}
|
||||
|
||||
reference front() {
|
||||
assert(!empty());
|
||||
return begin()[0];
|
||||
}
|
||||
const_reference front() const {
|
||||
assert(!empty());
|
||||
return begin()[0];
|
||||
}
|
||||
|
||||
reference back() {
|
||||
assert(!empty());
|
||||
return end()[-1];
|
||||
}
|
||||
const_reference back() const {
|
||||
assert(!empty());
|
||||
return end()[-1];
|
||||
}
|
||||
};
|
||||
|
||||
/// SmallVectorTemplateBase<isPodLike = false> - This is where we put method
|
||||
/// implementations that are designed to work with non-POD-like T's.
|
||||
template <typename T, bool isPodLike>
|
||||
class SmallVectorTemplateBase : public SmallVectorTemplateCommon<T> {
|
||||
protected:
|
||||
SmallVectorTemplateBase(size_t Size) : SmallVectorTemplateCommon<T>(Size) {}
|
||||
|
||||
static void destroy_range(T *S, T *E) {
|
||||
while (S != E) {
|
||||
--E;
|
||||
E->~T();
|
||||
}
|
||||
}
|
||||
|
||||
/// Move the range [I, E) into the uninitialized memory starting with "Dest",
|
||||
/// constructing elements as needed.
|
||||
template<typename It1, typename It2>
|
||||
static void uninitialized_move(It1 I, It1 E, It2 Dest) {
|
||||
std::uninitialized_copy(std::make_move_iterator(I),
|
||||
std::make_move_iterator(E), Dest);
|
||||
}
|
||||
|
||||
/// Copy the range [I, E) onto the uninitialized memory starting with "Dest",
|
||||
/// constructing elements as needed.
|
||||
template<typename It1, typename It2>
|
||||
static void uninitialized_copy(It1 I, It1 E, It2 Dest) {
|
||||
std::uninitialized_copy(I, E, Dest);
|
||||
}
|
||||
|
||||
/// Grow the allocated memory (without initializing new elements), doubling
|
||||
/// the size of the allocated memory. Guarantees space for at least one more
|
||||
/// element, or MinSize more elements if specified.
|
||||
void grow(size_t MinSize = 0);
|
||||
|
||||
public:
|
||||
void push_back(const T &Elt) {
|
||||
if (LLVM_UNLIKELY(this->EndX >= this->CapacityX))
|
||||
this->grow();
|
||||
::new ((void*) this->end()) T(Elt);
|
||||
this->setEnd(this->end()+1);
|
||||
}
|
||||
|
||||
void push_back(T &&Elt) {
|
||||
if (LLVM_UNLIKELY(this->EndX >= this->CapacityX))
|
||||
this->grow();
|
||||
::new ((void*) this->end()) T(::std::move(Elt));
|
||||
this->setEnd(this->end()+1);
|
||||
}
|
||||
|
||||
void pop_back() {
|
||||
this->setEnd(this->end()-1);
|
||||
this->end()->~T();
|
||||
}
|
||||
};
|
||||
|
||||
// Define this out-of-line to dissuade the C++ compiler from inlining it.
|
||||
template <typename T, bool isPodLike>
|
||||
void SmallVectorTemplateBase<T, isPodLike>::grow(size_t MinSize) {
|
||||
size_t CurCapacity = this->capacity();
|
||||
size_t CurSize = this->size();
|
||||
// Always grow, even from zero.
|
||||
size_t NewCapacity = size_t(NextPowerOf2(CurCapacity+2));
|
||||
if (NewCapacity < MinSize)
|
||||
NewCapacity = MinSize;
|
||||
T *NewElts = static_cast<T*>(malloc(NewCapacity*sizeof(T)));
|
||||
|
||||
// Move the elements over.
|
||||
this->uninitialized_move(this->begin(), this->end(), NewElts);
|
||||
|
||||
// Destroy the original elements.
|
||||
destroy_range(this->begin(), this->end());
|
||||
|
||||
// If this wasn't grown from the inline copy, deallocate the old space.
|
||||
if (!this->isSmall())
|
||||
free(this->begin());
|
||||
|
||||
this->setEnd(NewElts+CurSize);
|
||||
this->BeginX = NewElts;
|
||||
this->CapacityX = this->begin()+NewCapacity;
|
||||
}
|
||||
|
||||
|
||||
/// SmallVectorTemplateBase<isPodLike = true> - This is where we put method
|
||||
/// implementations that are designed to work with POD-like T's.
|
||||
template <typename T>
|
||||
class SmallVectorTemplateBase<T, true> : public SmallVectorTemplateCommon<T> {
|
||||
protected:
|
||||
SmallVectorTemplateBase(size_t Size) : SmallVectorTemplateCommon<T>(Size) {}
|
||||
|
||||
// No need to do a destroy loop for POD's.
|
||||
static void destroy_range(T *, T *) {}
|
||||
|
||||
/// Move the range [I, E) onto the uninitialized memory
|
||||
/// starting with "Dest", constructing elements into it as needed.
|
||||
template<typename It1, typename It2>
|
||||
static void uninitialized_move(It1 I, It1 E, It2 Dest) {
|
||||
// Just do a copy.
|
||||
uninitialized_copy(I, E, Dest);
|
||||
}
|
||||
|
||||
/// Copy the range [I, E) onto the uninitialized memory
|
||||
/// starting with "Dest", constructing elements into it as needed.
|
||||
template<typename It1, typename It2>
|
||||
static void uninitialized_copy(It1 I, It1 E, It2 Dest) {
|
||||
// Arbitrary iterator types; just use the basic implementation.
|
||||
std::uninitialized_copy(I, E, Dest);
|
||||
}
|
||||
|
||||
/// Copy the range [I, E) onto the uninitialized memory
|
||||
/// starting with "Dest", constructing elements into it as needed.
|
||||
template <typename T1, typename T2>
|
||||
static void uninitialized_copy(
|
||||
T1 *I, T1 *E, T2 *Dest,
|
||||
typename std::enable_if<std::is_same<typename std::remove_const<T1>::type,
|
||||
T2>::value>::type * = nullptr) {
|
||||
// Use memcpy for PODs iterated by pointers (which includes SmallVector
|
||||
// iterators): std::uninitialized_copy optimizes to memmove, but we can
|
||||
// use memcpy here. Note that I and E are iterators and thus might be
|
||||
// invalid for memcpy if they are equal.
|
||||
if (I != E)
|
||||
memcpy(Dest, I, (E - I) * sizeof(T));
|
||||
}
|
||||
|
||||
/// Double the size of the allocated memory, guaranteeing space for at
|
||||
/// least one more element or MinSize if specified.
|
||||
void grow(size_t MinSize = 0) {
|
||||
this->grow_pod(MinSize*sizeof(T), sizeof(T));
|
||||
}
|
||||
public:
|
||||
void push_back(const T &Elt) {
|
||||
if (LLVM_UNLIKELY(this->EndX >= this->CapacityX))
|
||||
this->grow();
|
||||
memcpy(this->end(), &Elt, sizeof(T));
|
||||
this->setEnd(this->end()+1);
|
||||
}
|
||||
|
||||
void pop_back() {
|
||||
this->setEnd(this->end()-1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// This class consists of common code factored out of the SmallVector class to
|
||||
/// reduce code duplication based on the SmallVector 'N' template parameter.
|
||||
template <typename T>
|
||||
class SmallVectorImpl : public SmallVectorTemplateBase<T, isPodLike<T>::value> {
|
||||
typedef SmallVectorTemplateBase<T, isPodLike<T>::value > SuperClass;
|
||||
|
||||
SmallVectorImpl(const SmallVectorImpl&) = delete;
|
||||
public:
|
||||
typedef typename SuperClass::iterator iterator;
|
||||
typedef typename SuperClass::const_iterator const_iterator;
|
||||
typedef typename SuperClass::size_type size_type;
|
||||
|
||||
protected:
|
||||
// Default ctor - Initialize to empty.
|
||||
explicit SmallVectorImpl(unsigned N)
|
||||
: SmallVectorTemplateBase<T, isPodLike<T>::value>(N*sizeof(T)) {
|
||||
}
|
||||
|
||||
public:
|
||||
~SmallVectorImpl() {
|
||||
// Destroy the constructed elements in the vector.
|
||||
this->destroy_range(this->begin(), this->end());
|
||||
|
||||
// If this wasn't grown from the inline copy, deallocate the old space.
|
||||
if (!this->isSmall())
|
||||
free(this->begin());
|
||||
}
|
||||
|
||||
|
||||
void clear() {
|
||||
this->destroy_range(this->begin(), this->end());
|
||||
this->EndX = this->BeginX;
|
||||
}
|
||||
|
||||
void resize(size_type N) {
|
||||
if (N < this->size()) {
|
||||
this->destroy_range(this->begin()+N, this->end());
|
||||
this->setEnd(this->begin()+N);
|
||||
} else if (N > this->size()) {
|
||||
if (this->capacity() < N)
|
||||
this->grow(N);
|
||||
for (auto I = this->end(), E = this->begin() + N; I != E; ++I)
|
||||
new (&*I) T();
|
||||
this->setEnd(this->begin()+N);
|
||||
}
|
||||
}
|
||||
|
||||
void resize(size_type N, const T &NV) {
|
||||
if (N < this->size()) {
|
||||
this->destroy_range(this->begin()+N, this->end());
|
||||
this->setEnd(this->begin()+N);
|
||||
} else if (N > this->size()) {
|
||||
if (this->capacity() < N)
|
||||
this->grow(N);
|
||||
std::uninitialized_fill(this->end(), this->begin()+N, NV);
|
||||
this->setEnd(this->begin()+N);
|
||||
}
|
||||
}
|
||||
|
||||
void reserve(size_type N) {
|
||||
if (this->capacity() < N)
|
||||
this->grow(N);
|
||||
}
|
||||
|
||||
T LLVM_ATTRIBUTE_UNUSED_RESULT pop_back_val() {
|
||||
T Result = ::std::move(this->back());
|
||||
this->pop_back();
|
||||
return Result;
|
||||
}
|
||||
|
||||
void swap(SmallVectorImpl &RHS);
|
||||
|
||||
/// Add the specified range to the end of the SmallVector.
|
||||
template<typename in_iter>
|
||||
void append(in_iter in_start, in_iter in_end) {
|
||||
size_type NumInputs = std::distance(in_start, in_end);
|
||||
// Grow allocated space if needed.
|
||||
if (NumInputs > size_type(this->capacity_ptr()-this->end()))
|
||||
this->grow(this->size()+NumInputs);
|
||||
|
||||
// Copy the new elements over.
|
||||
this->uninitialized_copy(in_start, in_end, this->end());
|
||||
this->setEnd(this->end() + NumInputs);
|
||||
}
|
||||
|
||||
/// Add the specified range to the end of the SmallVector.
|
||||
void append(size_type NumInputs, const T &Elt) {
|
||||
// Grow allocated space if needed.
|
||||
if (NumInputs > size_type(this->capacity_ptr()-this->end()))
|
||||
this->grow(this->size()+NumInputs);
|
||||
|
||||
// Copy the new elements over.
|
||||
std::uninitialized_fill_n(this->end(), NumInputs, Elt);
|
||||
this->setEnd(this->end() + NumInputs);
|
||||
}
|
||||
|
||||
void append(std::initializer_list<T> IL) {
|
||||
append(IL.begin(), IL.end());
|
||||
}
|
||||
|
||||
void assign(size_type NumElts, const T &Elt) {
|
||||
clear();
|
||||
if (this->capacity() < NumElts)
|
||||
this->grow(NumElts);
|
||||
this->setEnd(this->begin()+NumElts);
|
||||
std::uninitialized_fill(this->begin(), this->end(), Elt);
|
||||
}
|
||||
|
||||
void assign(std::initializer_list<T> IL) {
|
||||
clear();
|
||||
append(IL);
|
||||
}
|
||||
|
||||
iterator erase(const_iterator CI) {
|
||||
// Just cast away constness because this is a non-const member function.
|
||||
iterator I = const_cast<iterator>(CI);
|
||||
|
||||
assert(I >= this->begin() && "Iterator to erase is out of bounds.");
|
||||
assert(I < this->end() && "Erasing at past-the-end iterator.");
|
||||
|
||||
iterator N = I;
|
||||
// Shift all elts down one.
|
||||
std::move(I+1, this->end(), I);
|
||||
// Drop the last elt.
|
||||
this->pop_back();
|
||||
return(N);
|
||||
}
|
||||
|
||||
iterator erase(const_iterator CS, const_iterator CE) {
|
||||
// Just cast away constness because this is a non-const member function.
|
||||
iterator S = const_cast<iterator>(CS);
|
||||
iterator E = const_cast<iterator>(CE);
|
||||
|
||||
assert(S >= this->begin() && "Range to erase is out of bounds.");
|
||||
assert(S <= E && "Trying to erase invalid range.");
|
||||
assert(E <= this->end() && "Trying to erase past the end.");
|
||||
|
||||
iterator N = S;
|
||||
// Shift all elts down.
|
||||
iterator I = std::move(E, this->end(), S);
|
||||
// Drop the last elts.
|
||||
this->destroy_range(I, this->end());
|
||||
this->setEnd(I);
|
||||
return(N);
|
||||
}
|
||||
|
||||
iterator insert(iterator I, T &&Elt) {
|
||||
if (I == this->end()) { // Important special case for empty vector.
|
||||
this->push_back(::std::move(Elt));
|
||||
return this->end()-1;
|
||||
}
|
||||
|
||||
assert(I >= this->begin() && "Insertion iterator is out of bounds.");
|
||||
assert(I <= this->end() && "Inserting past the end of the vector.");
|
||||
|
||||
if (this->EndX >= this->CapacityX) {
|
||||
size_t EltNo = I-this->begin();
|
||||
this->grow();
|
||||
I = this->begin()+EltNo;
|
||||
}
|
||||
|
||||
::new ((void*) this->end()) T(::std::move(this->back()));
|
||||
// Push everything else over.
|
||||
std::move_backward(I, this->end()-1, this->end());
|
||||
this->setEnd(this->end()+1);
|
||||
|
||||
// If we just moved the element we're inserting, be sure to update
|
||||
// the reference.
|
||||
T *EltPtr = &Elt;
|
||||
if (I <= EltPtr && EltPtr < this->EndX)
|
||||
++EltPtr;
|
||||
|
||||
*I = ::std::move(*EltPtr);
|
||||
return I;
|
||||
}
|
||||
|
||||
iterator insert(iterator I, const T &Elt) {
|
||||
if (I == this->end()) { // Important special case for empty vector.
|
||||
this->push_back(Elt);
|
||||
return this->end()-1;
|
||||
}
|
||||
|
||||
assert(I >= this->begin() && "Insertion iterator is out of bounds.");
|
||||
assert(I <= this->end() && "Inserting past the end of the vector.");
|
||||
|
||||
if (this->EndX >= this->CapacityX) {
|
||||
size_t EltNo = I-this->begin();
|
||||
this->grow();
|
||||
I = this->begin()+EltNo;
|
||||
}
|
||||
::new ((void*) this->end()) T(std::move(this->back()));
|
||||
// Push everything else over.
|
||||
std::move_backward(I, this->end()-1, this->end());
|
||||
this->setEnd(this->end()+1);
|
||||
|
||||
// If we just moved the element we're inserting, be sure to update
|
||||
// the reference.
|
||||
const T *EltPtr = &Elt;
|
||||
if (I <= EltPtr && EltPtr < this->EndX)
|
||||
++EltPtr;
|
||||
|
||||
*I = *EltPtr;
|
||||
return I;
|
||||
}
|
||||
|
||||
iterator insert(iterator I, size_type NumToInsert, const T &Elt) {
|
||||
// Convert iterator to elt# to avoid invalidating iterator when we reserve()
|
||||
size_t InsertElt = I - this->begin();
|
||||
|
||||
if (I == this->end()) { // Important special case for empty vector.
|
||||
append(NumToInsert, Elt);
|
||||
return this->begin()+InsertElt;
|
||||
}
|
||||
|
||||
assert(I >= this->begin() && "Insertion iterator is out of bounds.");
|
||||
assert(I <= this->end() && "Inserting past the end of the vector.");
|
||||
|
||||
// Ensure there is enough space.
|
||||
reserve(this->size() + NumToInsert);
|
||||
|
||||
// Uninvalidate the iterator.
|
||||
I = this->begin()+InsertElt;
|
||||
|
||||
// If there are more elements between the insertion point and the end of the
|
||||
// range than there are being inserted, we can use a simple approach to
|
||||
// insertion. Since we already reserved space, we know that this won't
|
||||
// reallocate the vector.
|
||||
if (size_t(this->end()-I) >= NumToInsert) {
|
||||
T *OldEnd = this->end();
|
||||
append(std::move_iterator<iterator>(this->end() - NumToInsert),
|
||||
std::move_iterator<iterator>(this->end()));
|
||||
|
||||
// Copy the existing elements that get replaced.
|
||||
std::move_backward(I, OldEnd-NumToInsert, OldEnd);
|
||||
|
||||
std::fill_n(I, NumToInsert, Elt);
|
||||
return I;
|
||||
}
|
||||
|
||||
// Otherwise, we're inserting more elements than exist already, and we're
|
||||
// not inserting at the end.
|
||||
|
||||
// Move over the elements that we're about to overwrite.
|
||||
T *OldEnd = this->end();
|
||||
this->setEnd(this->end() + NumToInsert);
|
||||
size_t NumOverwritten = OldEnd-I;
|
||||
this->uninitialized_move(I, OldEnd, this->end()-NumOverwritten);
|
||||
|
||||
// Replace the overwritten part.
|
||||
std::fill_n(I, NumOverwritten, Elt);
|
||||
|
||||
// Insert the non-overwritten middle part.
|
||||
std::uninitialized_fill_n(OldEnd, NumToInsert-NumOverwritten, Elt);
|
||||
return I;
|
||||
}
|
||||
|
||||
template<typename ItTy>
|
||||
iterator insert(iterator I, ItTy From, ItTy To) {
|
||||
// Convert iterator to elt# to avoid invalidating iterator when we reserve()
|
||||
size_t InsertElt = I - this->begin();
|
||||
|
||||
if (I == this->end()) { // Important special case for empty vector.
|
||||
append(From, To);
|
||||
return this->begin()+InsertElt;
|
||||
}
|
||||
|
||||
assert(I >= this->begin() && "Insertion iterator is out of bounds.");
|
||||
assert(I <= this->end() && "Inserting past the end of the vector.");
|
||||
|
||||
size_t NumToInsert = std::distance(From, To);
|
||||
|
||||
// Ensure there is enough space.
|
||||
reserve(this->size() + NumToInsert);
|
||||
|
||||
// Uninvalidate the iterator.
|
||||
I = this->begin()+InsertElt;
|
||||
|
||||
// If there are more elements between the insertion point and the end of the
|
||||
// range than there are being inserted, we can use a simple approach to
|
||||
// insertion. Since we already reserved space, we know that this won't
|
||||
// reallocate the vector.
|
||||
if (size_t(this->end()-I) >= NumToInsert) {
|
||||
T *OldEnd = this->end();
|
||||
append(std::move_iterator<iterator>(this->end() - NumToInsert),
|
||||
std::move_iterator<iterator>(this->end()));
|
||||
|
||||
// Copy the existing elements that get replaced.
|
||||
std::move_backward(I, OldEnd-NumToInsert, OldEnd);
|
||||
|
||||
std::copy(From, To, I);
|
||||
return I;
|
||||
}
|
||||
|
||||
// Otherwise, we're inserting more elements than exist already, and we're
|
||||
// not inserting at the end.
|
||||
|
||||
// Move over the elements that we're about to overwrite.
|
||||
T *OldEnd = this->end();
|
||||
this->setEnd(this->end() + NumToInsert);
|
||||
size_t NumOverwritten = OldEnd-I;
|
||||
this->uninitialized_move(I, OldEnd, this->end()-NumOverwritten);
|
||||
|
||||
// Replace the overwritten part.
|
||||
for (T *J = I; NumOverwritten > 0; --NumOverwritten) {
|
||||
*J = *From;
|
||||
++J; ++From;
|
||||
}
|
||||
|
||||
// Insert the non-overwritten middle part.
|
||||
this->uninitialized_copy(From, To, OldEnd);
|
||||
return I;
|
||||
}
|
||||
|
||||
void insert(iterator I, std::initializer_list<T> IL) {
|
||||
insert(I, IL.begin(), IL.end());
|
||||
}
|
||||
|
||||
template <typename... ArgTypes> void emplace_back(ArgTypes &&... Args) {
|
||||
if (LLVM_UNLIKELY(this->EndX >= this->CapacityX))
|
||||
this->grow();
|
||||
::new ((void *)this->end()) T(std::forward<ArgTypes>(Args)...);
|
||||
this->setEnd(this->end() + 1);
|
||||
}
|
||||
|
||||
SmallVectorImpl &operator=(const SmallVectorImpl &RHS);
|
||||
|
||||
SmallVectorImpl &operator=(SmallVectorImpl &&RHS);
|
||||
|
||||
bool operator==(const SmallVectorImpl &RHS) const {
|
||||
if (this->size() != RHS.size()) return false;
|
||||
return std::equal(this->begin(), this->end(), RHS.begin());
|
||||
}
|
||||
bool operator!=(const SmallVectorImpl &RHS) const {
|
||||
return !(*this == RHS);
|
||||
}
|
||||
|
||||
bool operator<(const SmallVectorImpl &RHS) const {
|
||||
return std::lexicographical_compare(this->begin(), this->end(),
|
||||
RHS.begin(), RHS.end());
|
||||
}
|
||||
|
||||
/// Set the array size to \p N, which the current array must have enough
|
||||
/// capacity for.
|
||||
///
|
||||
/// This does not construct or destroy any elements in the vector.
|
||||
///
|
||||
/// Clients can use this in conjunction with capacity() to write past the end
|
||||
/// of the buffer when they know that more elements are available, and only
|
||||
/// update the size later. This avoids the cost of value initializing elements
|
||||
/// which will only be overwritten.
|
||||
void set_size(size_type N) {
|
||||
assert(N <= this->capacity());
|
||||
this->setEnd(this->begin() + N);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
void SmallVectorImpl<T>::swap(SmallVectorImpl<T> &RHS) {
|
||||
if (this == &RHS) return;
|
||||
|
||||
// We can only avoid copying elements if neither vector is small.
|
||||
if (!this->isSmall() && !RHS.isSmall()) {
|
||||
std::swap(this->BeginX, RHS.BeginX);
|
||||
std::swap(this->EndX, RHS.EndX);
|
||||
std::swap(this->CapacityX, RHS.CapacityX);
|
||||
return;
|
||||
}
|
||||
if (RHS.size() > this->capacity())
|
||||
this->grow(RHS.size());
|
||||
if (this->size() > RHS.capacity())
|
||||
RHS.grow(this->size());
|
||||
|
||||
// Swap the shared elements.
|
||||
size_t NumShared = this->size();
|
||||
if (NumShared > RHS.size()) NumShared = RHS.size();
|
||||
for (size_type i = 0; i != NumShared; ++i)
|
||||
std::swap((*this)[i], RHS[i]);
|
||||
|
||||
// Copy over the extra elts.
|
||||
if (this->size() > RHS.size()) {
|
||||
size_t EltDiff = this->size() - RHS.size();
|
||||
this->uninitialized_copy(this->begin()+NumShared, this->end(), RHS.end());
|
||||
RHS.setEnd(RHS.end()+EltDiff);
|
||||
this->destroy_range(this->begin()+NumShared, this->end());
|
||||
this->setEnd(this->begin()+NumShared);
|
||||
} else if (RHS.size() > this->size()) {
|
||||
size_t EltDiff = RHS.size() - this->size();
|
||||
this->uninitialized_copy(RHS.begin()+NumShared, RHS.end(), this->end());
|
||||
this->setEnd(this->end() + EltDiff);
|
||||
this->destroy_range(RHS.begin()+NumShared, RHS.end());
|
||||
RHS.setEnd(RHS.begin()+NumShared);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
SmallVectorImpl<T> &SmallVectorImpl<T>::
|
||||
operator=(const SmallVectorImpl<T> &RHS) {
|
||||
// Avoid self-assignment.
|
||||
if (this == &RHS) return *this;
|
||||
|
||||
// If we already have sufficient space, assign the common elements, then
|
||||
// destroy any excess.
|
||||
size_t RHSSize = RHS.size();
|
||||
size_t CurSize = this->size();
|
||||
if (CurSize >= RHSSize) {
|
||||
// Assign common elements.
|
||||
iterator NewEnd;
|
||||
if (RHSSize)
|
||||
NewEnd = std::copy(RHS.begin(), RHS.begin()+RHSSize, this->begin());
|
||||
else
|
||||
NewEnd = this->begin();
|
||||
|
||||
// Destroy excess elements.
|
||||
this->destroy_range(NewEnd, this->end());
|
||||
|
||||
// Trim.
|
||||
this->setEnd(NewEnd);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// If we have to grow to have enough elements, destroy the current elements.
|
||||
// This allows us to avoid copying them during the grow.
|
||||
// FIXME: don't do this if they're efficiently moveable.
|
||||
if (this->capacity() < RHSSize) {
|
||||
// Destroy current elements.
|
||||
this->destroy_range(this->begin(), this->end());
|
||||
this->setEnd(this->begin());
|
||||
CurSize = 0;
|
||||
this->grow(RHSSize);
|
||||
} else if (CurSize) {
|
||||
// Otherwise, use assignment for the already-constructed elements.
|
||||
std::copy(RHS.begin(), RHS.begin()+CurSize, this->begin());
|
||||
}
|
||||
|
||||
// Copy construct the new elements in place.
|
||||
this->uninitialized_copy(RHS.begin()+CurSize, RHS.end(),
|
||||
this->begin()+CurSize);
|
||||
|
||||
// Set end.
|
||||
this->setEnd(this->begin()+RHSSize);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
SmallVectorImpl<T> &SmallVectorImpl<T>::operator=(SmallVectorImpl<T> &&RHS) {
|
||||
// Avoid self-assignment.
|
||||
if (this == &RHS) return *this;
|
||||
|
||||
// If the RHS isn't small, clear this vector and then steal its buffer.
|
||||
if (!RHS.isSmall()) {
|
||||
this->destroy_range(this->begin(), this->end());
|
||||
if (!this->isSmall()) free(this->begin());
|
||||
this->BeginX = RHS.BeginX;
|
||||
this->EndX = RHS.EndX;
|
||||
this->CapacityX = RHS.CapacityX;
|
||||
RHS.resetToSmall();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// If we already have sufficient space, assign the common elements, then
|
||||
// destroy any excess.
|
||||
size_t RHSSize = RHS.size();
|
||||
size_t CurSize = this->size();
|
||||
if (CurSize >= RHSSize) {
|
||||
// Assign common elements.
|
||||
iterator NewEnd = this->begin();
|
||||
if (RHSSize)
|
||||
NewEnd = std::move(RHS.begin(), RHS.end(), NewEnd);
|
||||
|
||||
// Destroy excess elements and trim the bounds.
|
||||
this->destroy_range(NewEnd, this->end());
|
||||
this->setEnd(NewEnd);
|
||||
|
||||
// Clear the RHS.
|
||||
RHS.clear();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// If we have to grow to have enough elements, destroy the current elements.
|
||||
// This allows us to avoid copying them during the grow.
|
||||
// FIXME: this may not actually make any sense if we can efficiently move
|
||||
// elements.
|
||||
if (this->capacity() < RHSSize) {
|
||||
// Destroy current elements.
|
||||
this->destroy_range(this->begin(), this->end());
|
||||
this->setEnd(this->begin());
|
||||
CurSize = 0;
|
||||
this->grow(RHSSize);
|
||||
} else if (CurSize) {
|
||||
// Otherwise, use assignment for the already-constructed elements.
|
||||
std::move(RHS.begin(), RHS.begin()+CurSize, this->begin());
|
||||
}
|
||||
|
||||
// Move-construct the new elements in place.
|
||||
this->uninitialized_move(RHS.begin()+CurSize, RHS.end(),
|
||||
this->begin()+CurSize);
|
||||
|
||||
// Set end.
|
||||
this->setEnd(this->begin()+RHSSize);
|
||||
|
||||
RHS.clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Storage for the SmallVector elements which aren't contained in
|
||||
/// SmallVectorTemplateCommon. There are 'N-1' elements here. The remaining '1'
|
||||
/// element is in the base class. This is specialized for the N=1 and N=0 cases
|
||||
/// to avoid allocating unnecessary storage.
|
||||
template <typename T, unsigned N>
|
||||
struct SmallVectorStorage {
|
||||
typename SmallVectorTemplateCommon<T>::U InlineElts[N - 1];
|
||||
};
|
||||
template <typename T> struct SmallVectorStorage<T, 1> {};
|
||||
template <typename T> struct SmallVectorStorage<T, 0> {};
|
||||
|
||||
/// This is a 'vector' (really, a variable-sized array), optimized
|
||||
/// for the case when the array is small. It contains some number of elements
|
||||
/// in-place, which allows it to avoid heap allocation when the actual number of
|
||||
/// elements is below that threshold. This allows normal "small" cases to be
|
||||
/// fast without losing generality for large inputs.
|
||||
///
|
||||
/// Note that this does not attempt to be exception safe.
|
||||
///
|
||||
template <typename T, unsigned N>
|
||||
class SmallVector : public SmallVectorImpl<T> {
|
||||
/// Inline space for elements which aren't stored in the base class.
|
||||
SmallVectorStorage<T, N> Storage;
|
||||
public:
|
||||
SmallVector() : SmallVectorImpl<T>(N) {
|
||||
}
|
||||
|
||||
explicit SmallVector(size_t Size, const T &Value = T())
|
||||
: SmallVectorImpl<T>(N) {
|
||||
this->assign(Size, Value);
|
||||
}
|
||||
|
||||
template<typename ItTy>
|
||||
SmallVector(ItTy S, ItTy E) : SmallVectorImpl<T>(N) {
|
||||
this->append(S, E);
|
||||
}
|
||||
|
||||
template <typename RangeTy>
|
||||
explicit SmallVector(const llvm::iterator_range<RangeTy> R)
|
||||
: SmallVectorImpl<T>(N) {
|
||||
this->append(R.begin(), R.end());
|
||||
}
|
||||
|
||||
SmallVector(std::initializer_list<T> IL) : SmallVectorImpl<T>(N) {
|
||||
this->assign(IL);
|
||||
}
|
||||
|
||||
SmallVector(const SmallVector &RHS) : SmallVectorImpl<T>(N) {
|
||||
if (!RHS.empty())
|
||||
SmallVectorImpl<T>::operator=(RHS);
|
||||
}
|
||||
|
||||
const SmallVector &operator=(const SmallVector &RHS) {
|
||||
SmallVectorImpl<T>::operator=(RHS);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SmallVector(SmallVector &&RHS) : SmallVectorImpl<T>(N) {
|
||||
if (!RHS.empty())
|
||||
SmallVectorImpl<T>::operator=(::std::move(RHS));
|
||||
}
|
||||
|
||||
const SmallVector &operator=(SmallVector &&RHS) {
|
||||
SmallVectorImpl<T>::operator=(::std::move(RHS));
|
||||
return *this;
|
||||
}
|
||||
|
||||
SmallVector(SmallVectorImpl<T> &&RHS) : SmallVectorImpl<T>(N) {
|
||||
if (!RHS.empty())
|
||||
SmallVectorImpl<T>::operator=(::std::move(RHS));
|
||||
}
|
||||
|
||||
const SmallVector &operator=(SmallVectorImpl<T> &&RHS) {
|
||||
SmallVectorImpl<T>::operator=(::std::move(RHS));
|
||||
return *this;
|
||||
}
|
||||
|
||||
const SmallVector &operator=(std::initializer_list<T> IL) {
|
||||
this->assign(IL);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, unsigned N>
|
||||
static inline size_t capacity_in_bytes(const SmallVector<T, N> &X) {
|
||||
return X.capacity_in_bytes();
|
||||
}
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
namespace std {
|
||||
/// Implement std::swap in terms of SmallVector swap.
|
||||
template<typename T>
|
||||
inline void
|
||||
swap(llvm::SmallVectorImpl<T> &LHS, llvm::SmallVectorImpl<T> &RHS) {
|
||||
LHS.swap(RHS);
|
||||
}
|
||||
|
||||
/// Implement std::swap in terms of SmallVector swap.
|
||||
template<typename T, unsigned N>
|
||||
inline void
|
||||
swap(llvm::SmallVector<T, N> &LHS, llvm::SmallVector<T, N> &RHS) {
|
||||
LHS.swap(RHS);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
197
src/main/native/include/llvm/StringExtras.h
Normal file
197
src/main/native/include/llvm/StringExtras.h
Normal file
@@ -0,0 +1,197 @@
|
||||
//===-- llvm/ADT/StringExtras.h - Useful string functions -------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains some functions that are useful when dealing with strings.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_STRINGEXTRAS_H
|
||||
#define LLVM_ADT_STRINGEXTRAS_H
|
||||
|
||||
#include "llvm/StringRef.h"
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
|
||||
namespace llvm {
|
||||
template<typename T> class SmallVectorImpl;
|
||||
|
||||
/// hexdigit - Return the hexadecimal character for the
|
||||
/// given number \p X (which should be less than 16).
|
||||
static inline char hexdigit(unsigned X, bool LowerCase = false) {
|
||||
const char HexChar = LowerCase ? 'a' : 'A';
|
||||
return X < 10 ? '0' + X : HexChar + X - 10;
|
||||
}
|
||||
|
||||
/// Construct a string ref from a boolean.
|
||||
static inline StringRef toStringRef(bool B) {
|
||||
return StringRef(B ? "true" : "false");
|
||||
}
|
||||
|
||||
/// Interpret the given character \p C as a hexadecimal digit and return its
|
||||
/// value.
|
||||
///
|
||||
/// If \p C is not a valid hex digit, -1U is returned.
|
||||
static inline unsigned hexDigitValue(char C) {
|
||||
if (C >= '0' && C <= '9') return C-'0';
|
||||
if (C >= 'a' && C <= 'f') return C-'a'+10U;
|
||||
if (C >= 'A' && C <= 'F') return C-'A'+10U;
|
||||
return -1U;
|
||||
}
|
||||
|
||||
static inline std::string utohexstr(uint64_t X, bool LowerCase = false) {
|
||||
char Buffer[17];
|
||||
char *BufPtr = std::end(Buffer);
|
||||
|
||||
if (X == 0) *--BufPtr = '0';
|
||||
|
||||
while (X) {
|
||||
unsigned char Mod = static_cast<unsigned char>(X) & 15;
|
||||
*--BufPtr = hexdigit(Mod, LowerCase);
|
||||
X >>= 4;
|
||||
}
|
||||
|
||||
return std::string(BufPtr, std::end(Buffer));
|
||||
}
|
||||
|
||||
/// Convert buffer \p Input to its hexadecimal representation.
|
||||
/// The returned string is double the size of \p Input.
|
||||
static inline std::string toHex(StringRef Input) {
|
||||
static const char *const LUT = "0123456789ABCDEF";
|
||||
size_t Length = Input.size();
|
||||
|
||||
std::string Output;
|
||||
Output.reserve(2 * Length);
|
||||
for (size_t i = 0; i < Length; ++i) {
|
||||
const unsigned char c = Input[i];
|
||||
Output.push_back(LUT[c >> 4]);
|
||||
Output.push_back(LUT[c & 15]);
|
||||
}
|
||||
return Output;
|
||||
}
|
||||
|
||||
static inline std::string utostr(uint64_t X, bool isNeg = false) {
|
||||
char Buffer[21];
|
||||
char *BufPtr = std::end(Buffer);
|
||||
|
||||
if (X == 0) *--BufPtr = '0'; // Handle special case...
|
||||
|
||||
while (X) {
|
||||
*--BufPtr = '0' + char(X % 10);
|
||||
X /= 10;
|
||||
}
|
||||
|
||||
if (isNeg) *--BufPtr = '-'; // Add negative sign...
|
||||
return std::string(BufPtr, std::end(Buffer));
|
||||
}
|
||||
|
||||
|
||||
static inline std::string itostr(int64_t X) {
|
||||
if (X < 0)
|
||||
return utostr(static_cast<uint64_t>(-X), true);
|
||||
else
|
||||
return utostr(static_cast<uint64_t>(X));
|
||||
}
|
||||
|
||||
/// StrInStrNoCase - Portable version of strcasestr. Locates the first
|
||||
/// occurrence of string 's1' in string 's2', ignoring case. Returns
|
||||
/// the offset of s2 in s1 or npos if s2 cannot be found.
|
||||
StringRef::size_type StrInStrNoCase(StringRef s1, StringRef s2);
|
||||
|
||||
/// getToken - This function extracts one token from source, ignoring any
|
||||
/// leading characters that appear in the Delimiters string, and ending the
|
||||
/// token at any of the characters that appear in the Delimiters string. If
|
||||
/// there are no tokens in the source string, an empty string is returned.
|
||||
/// The function returns a pair containing the extracted token and the
|
||||
/// remaining tail string.
|
||||
std::pair<StringRef, StringRef> getToken(StringRef Source,
|
||||
StringRef Delimiters = " \t\n\v\f\r");
|
||||
|
||||
/// SplitString - Split up the specified string according to the specified
|
||||
/// delimiters, appending the result fragments to the output list.
|
||||
void SplitString(StringRef Source,
|
||||
SmallVectorImpl<StringRef> &OutFragments,
|
||||
StringRef Delimiters = " \t\n\v\f\r");
|
||||
|
||||
/// HashString - Hash function for strings.
|
||||
///
|
||||
/// This is the Bernstein hash function.
|
||||
//
|
||||
// FIXME: Investigate whether a modified bernstein hash function performs
|
||||
// better: http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx
|
||||
// X*33+c -> X*33^c
|
||||
static inline unsigned HashString(StringRef Str, unsigned Result = 0) {
|
||||
for (StringRef::size_type i = 0, e = Str.size(); i != e; ++i)
|
||||
Result = Result * 33 + (unsigned char)Str[i];
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// Returns the English suffix for an ordinal integer (-st, -nd, -rd, -th).
|
||||
static inline StringRef getOrdinalSuffix(unsigned Val) {
|
||||
// It is critically important that we do this perfectly for
|
||||
// user-written sequences with over 100 elements.
|
||||
switch (Val % 100) {
|
||||
case 11:
|
||||
case 12:
|
||||
case 13:
|
||||
return "th";
|
||||
default:
|
||||
switch (Val % 10) {
|
||||
case 1: return "st";
|
||||
case 2: return "nd";
|
||||
case 3: return "rd";
|
||||
default: return "th";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename IteratorT>
|
||||
inline std::string join_impl(IteratorT Begin, IteratorT End,
|
||||
StringRef Separator, std::input_iterator_tag) {
|
||||
std::string S;
|
||||
if (Begin == End)
|
||||
return S;
|
||||
|
||||
S += (*Begin);
|
||||
while (++Begin != End) {
|
||||
S += Separator;
|
||||
S += (*Begin);
|
||||
}
|
||||
return S;
|
||||
}
|
||||
|
||||
template <typename IteratorT>
|
||||
inline std::string join_impl(IteratorT Begin, IteratorT End,
|
||||
StringRef Separator, std::forward_iterator_tag) {
|
||||
std::string S;
|
||||
if (Begin == End)
|
||||
return S;
|
||||
|
||||
size_t Len = (std::distance(Begin, End) - 1) * Separator.size();
|
||||
for (IteratorT I = Begin; I != End; ++I)
|
||||
Len += (*Begin).size();
|
||||
S.reserve(Len);
|
||||
S += (*Begin);
|
||||
while (++Begin != End) {
|
||||
S += Separator;
|
||||
S += (*Begin);
|
||||
}
|
||||
return S;
|
||||
}
|
||||
|
||||
/// Joins the strings in the range [Begin, End), adding Separator between
|
||||
/// the elements.
|
||||
template <typename IteratorT>
|
||||
inline std::string join(IteratorT Begin, IteratorT End, StringRef Separator) {
|
||||
typedef typename std::iterator_traits<IteratorT>::iterator_category tag;
|
||||
return join_impl(Begin, End, Separator, tag());
|
||||
}
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
||||
476
src/main/native/include/llvm/StringMap.h
Normal file
476
src/main/native/include/llvm/StringMap.h
Normal file
@@ -0,0 +1,476 @@
|
||||
//===--- StringMap.h - String Hash table map interface ----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the StringMap class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_STRINGMAP_H
|
||||
#define LLVM_ADT_STRINGMAP_H
|
||||
|
||||
#include "llvm/StringRef.h"
|
||||
#include "llvm/PointerLikeTypeTraits.h"
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
template<typename ValueT>
|
||||
class StringMapConstIterator;
|
||||
template<typename ValueT>
|
||||
class StringMapIterator;
|
||||
template<typename ValueTy>
|
||||
class StringMapEntry;
|
||||
|
||||
/// StringMapEntryBase - Shared base class of StringMapEntry instances.
|
||||
class StringMapEntryBase {
|
||||
unsigned StrLen;
|
||||
|
||||
public:
|
||||
explicit StringMapEntryBase(unsigned Len) : StrLen(Len) {}
|
||||
|
||||
unsigned getKeyLength() const { return StrLen; }
|
||||
};
|
||||
|
||||
/// StringMapImpl - This is the base class of StringMap that is shared among
|
||||
/// all of its instantiations.
|
||||
class StringMapImpl {
|
||||
protected:
|
||||
// Array of NumBuckets pointers to entries, null pointers are holes.
|
||||
// TheTable[NumBuckets] contains a sentinel value for easy iteration. Followed
|
||||
// by an array of the actual hash values as unsigned integers.
|
||||
StringMapEntryBase **TheTable;
|
||||
unsigned NumBuckets;
|
||||
unsigned NumItems;
|
||||
unsigned NumTombstones;
|
||||
unsigned ItemSize;
|
||||
|
||||
protected:
|
||||
explicit StringMapImpl(unsigned itemSize)
|
||||
: TheTable(nullptr),
|
||||
// Initialize the map with zero buckets to allocation.
|
||||
NumBuckets(0), NumItems(0), NumTombstones(0), ItemSize(itemSize) {}
|
||||
StringMapImpl(StringMapImpl &&RHS)
|
||||
: TheTable(RHS.TheTable), NumBuckets(RHS.NumBuckets),
|
||||
NumItems(RHS.NumItems), NumTombstones(RHS.NumTombstones),
|
||||
ItemSize(RHS.ItemSize) {
|
||||
RHS.TheTable = nullptr;
|
||||
RHS.NumBuckets = 0;
|
||||
RHS.NumItems = 0;
|
||||
RHS.NumTombstones = 0;
|
||||
}
|
||||
|
||||
StringMapImpl(unsigned InitSize, unsigned ItemSize);
|
||||
unsigned RehashTable(unsigned BucketNo = 0);
|
||||
|
||||
/// LookupBucketFor - Look up the bucket that the specified string should end
|
||||
/// up in. If it already exists as a key in the map, the Item pointer for the
|
||||
/// specified bucket will be non-null. Otherwise, it will be null. In either
|
||||
/// case, the FullHashValue field of the bucket will be set to the hash value
|
||||
/// of the string.
|
||||
unsigned LookupBucketFor(StringRef Key);
|
||||
|
||||
/// FindKey - Look up the bucket that contains the specified key. If it exists
|
||||
/// in the map, return the bucket number of the key. Otherwise return -1.
|
||||
/// This does not modify the map.
|
||||
int FindKey(StringRef Key) const;
|
||||
|
||||
/// RemoveKey - Remove the specified StringMapEntry from the table, but do not
|
||||
/// delete it. This aborts if the value isn't in the table.
|
||||
void RemoveKey(StringMapEntryBase *V);
|
||||
|
||||
/// RemoveKey - Remove the StringMapEntry for the specified key from the
|
||||
/// table, returning it. If the key is not in the table, this returns null.
|
||||
StringMapEntryBase *RemoveKey(StringRef Key);
|
||||
|
||||
/// Allocate the table with the specified number of buckets and otherwise
|
||||
/// setup the map as empty.
|
||||
void init(unsigned Size);
|
||||
|
||||
public:
|
||||
static StringMapEntryBase *getTombstoneVal() {
|
||||
uintptr_t Val = static_cast<uintptr_t>(-1);
|
||||
Val <<= PointerLikeTypeTraits<StringMapEntryBase *>::NumLowBitsAvailable;
|
||||
return reinterpret_cast<StringMapEntryBase *>(Val);
|
||||
}
|
||||
|
||||
unsigned getNumBuckets() const { return NumBuckets; }
|
||||
unsigned getNumItems() const { return NumItems; }
|
||||
|
||||
bool empty() const { return NumItems == 0; }
|
||||
unsigned size() const { return NumItems; }
|
||||
|
||||
void swap(StringMapImpl &Other) {
|
||||
std::swap(TheTable, Other.TheTable);
|
||||
std::swap(NumBuckets, Other.NumBuckets);
|
||||
std::swap(NumItems, Other.NumItems);
|
||||
std::swap(NumTombstones, Other.NumTombstones);
|
||||
}
|
||||
};
|
||||
|
||||
/// StringMapEntry - This is used to represent one value that is inserted into
|
||||
/// a StringMap. It contains the Value itself and the key: the string length
|
||||
/// and data.
|
||||
template<typename ValueTy>
|
||||
class StringMapEntry : public StringMapEntryBase {
|
||||
StringMapEntry(StringMapEntry &E) = delete;
|
||||
|
||||
public:
|
||||
ValueTy second;
|
||||
|
||||
explicit StringMapEntry(unsigned strLen)
|
||||
: StringMapEntryBase(strLen), second() {}
|
||||
template <typename... InitTy>
|
||||
StringMapEntry(unsigned strLen, InitTy &&... InitVals)
|
||||
: StringMapEntryBase(strLen), second(std::forward<InitTy>(InitVals)...) {}
|
||||
|
||||
StringRef getKey() const {
|
||||
return StringRef(getKeyData(), getKeyLength());
|
||||
}
|
||||
|
||||
const ValueTy &getValue() const { return second; }
|
||||
ValueTy &getValue() { return second; }
|
||||
|
||||
void setValue(const ValueTy &V) { second = V; }
|
||||
|
||||
/// getKeyData - Return the start of the string data that is the key for this
|
||||
/// value. The string data is always stored immediately after the
|
||||
/// StringMapEntry object.
|
||||
const char *getKeyData() const {return reinterpret_cast<const char*>(this+1);}
|
||||
|
||||
StringRef first() const { return StringRef(getKeyData(), getKeyLength()); }
|
||||
|
||||
/// Create a StringMapEntry for the specified key construct the value using
|
||||
/// \p InitiVals.
|
||||
template <typename... InitTy>
|
||||
static StringMapEntry *Create(StringRef Key, InitTy &&... InitVals) {
|
||||
unsigned KeyLength = Key.size();
|
||||
|
||||
// Allocate a new item with space for the string at the end and a null
|
||||
// terminator.
|
||||
unsigned AllocSize = static_cast<unsigned>(sizeof(StringMapEntry))+
|
||||
KeyLength+1;
|
||||
|
||||
StringMapEntry *NewItem =
|
||||
static_cast<StringMapEntry*>(std::malloc(AllocSize));
|
||||
|
||||
// Construct the value.
|
||||
new (NewItem) StringMapEntry(KeyLength, std::forward<InitTy>(InitVals)...);
|
||||
|
||||
// Copy the string information.
|
||||
char *StrBuffer = const_cast<char*>(NewItem->getKeyData());
|
||||
if (KeyLength > 0)
|
||||
memcpy(StrBuffer, Key.data(), KeyLength);
|
||||
StrBuffer[KeyLength] = 0; // Null terminate for convenience of clients.
|
||||
return NewItem;
|
||||
}
|
||||
|
||||
static StringMapEntry *Create(StringRef Key) {
|
||||
return Create(Key, ValueTy());
|
||||
}
|
||||
|
||||
/// GetStringMapEntryFromKeyData - Given key data that is known to be embedded
|
||||
/// into a StringMapEntry, return the StringMapEntry itself.
|
||||
static StringMapEntry &GetStringMapEntryFromKeyData(const char *KeyData) {
|
||||
char *Ptr = const_cast<char*>(KeyData) - sizeof(StringMapEntry<ValueTy>);
|
||||
return *reinterpret_cast<StringMapEntry*>(Ptr);
|
||||
}
|
||||
|
||||
/// Destroy - Destroy this StringMapEntry, releasing memory back to the
|
||||
/// specified allocator.
|
||||
void Destroy() {
|
||||
// Free memory referenced by the item.
|
||||
this->~StringMapEntry();
|
||||
std::free(static_cast<void *>(this));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// StringMap - This is an unconventional map that is specialized for handling
|
||||
/// keys that are "strings", which are basically ranges of bytes. This does some
|
||||
/// funky memory allocation and hashing things to make it extremely efficient,
|
||||
/// storing the string data *after* the value in the map.
|
||||
template<typename ValueTy>
|
||||
class StringMap : public StringMapImpl {
|
||||
public:
|
||||
typedef StringMapEntry<ValueTy> MapEntryTy;
|
||||
|
||||
StringMap() : StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))) {}
|
||||
explicit StringMap(unsigned InitialSize)
|
||||
: StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))) {}
|
||||
|
||||
StringMap(std::initializer_list<std::pair<StringRef, ValueTy>> List)
|
||||
: StringMapImpl(List.size(), static_cast<unsigned>(sizeof(MapEntryTy))) {
|
||||
for (const auto &P : List) {
|
||||
insert(P);
|
||||
}
|
||||
}
|
||||
|
||||
StringMap(StringMap &&RHS)
|
||||
: StringMapImpl(std::move(RHS)) {}
|
||||
|
||||
StringMap &operator=(StringMap RHS) {
|
||||
StringMapImpl::swap(RHS);
|
||||
return *this;
|
||||
}
|
||||
|
||||
StringMap(const StringMap &RHS) :
|
||||
StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))) {
|
||||
if (RHS.empty())
|
||||
return;
|
||||
|
||||
// Allocate TheTable of the same size as RHS's TheTable, and set the
|
||||
// sentinel appropriately (and NumBuckets).
|
||||
init(RHS.NumBuckets);
|
||||
unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1),
|
||||
*RHSHashTable = (unsigned *)(RHS.TheTable + NumBuckets + 1);
|
||||
|
||||
NumItems = RHS.NumItems;
|
||||
NumTombstones = RHS.NumTombstones;
|
||||
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
|
||||
StringMapEntryBase *Bucket = RHS.TheTable[I];
|
||||
if (!Bucket || Bucket == getTombstoneVal()) {
|
||||
TheTable[I] = Bucket;
|
||||
continue;
|
||||
}
|
||||
|
||||
TheTable[I] = MapEntryTy::Create(
|
||||
static_cast<MapEntryTy *>(Bucket)->getKey(),
|
||||
static_cast<MapEntryTy *>(Bucket)->getValue());
|
||||
HashTable[I] = RHSHashTable[I];
|
||||
}
|
||||
|
||||
// Note that here we've copied everything from the RHS into this object,
|
||||
// tombstones included. We could, instead, have re-probed for each key to
|
||||
// instantiate this new object without any tombstone buckets. The
|
||||
// assumption here is that items are rarely deleted from most StringMaps,
|
||||
// and so tombstones are rare, so the cost of re-probing for all inputs is
|
||||
// not worthwhile.
|
||||
}
|
||||
|
||||
|
||||
typedef const char* key_type;
|
||||
typedef ValueTy mapped_type;
|
||||
typedef StringMapEntry<ValueTy> value_type;
|
||||
typedef size_t size_type;
|
||||
|
||||
typedef StringMapConstIterator<ValueTy> const_iterator;
|
||||
typedef StringMapIterator<ValueTy> iterator;
|
||||
|
||||
iterator begin() {
|
||||
return iterator(TheTable, NumBuckets == 0);
|
||||
}
|
||||
iterator end() {
|
||||
return iterator(TheTable+NumBuckets, true);
|
||||
}
|
||||
const_iterator begin() const {
|
||||
return const_iterator(TheTable, NumBuckets == 0);
|
||||
}
|
||||
const_iterator end() const {
|
||||
return const_iterator(TheTable+NumBuckets, true);
|
||||
}
|
||||
|
||||
iterator find(StringRef Key) {
|
||||
int Bucket = FindKey(Key);
|
||||
if (Bucket == -1) return end();
|
||||
return iterator(TheTable+Bucket, true);
|
||||
}
|
||||
|
||||
const_iterator find(StringRef Key) const {
|
||||
int Bucket = FindKey(Key);
|
||||
if (Bucket == -1) return end();
|
||||
return const_iterator(TheTable+Bucket, true);
|
||||
}
|
||||
|
||||
/// lookup - Return the entry for the specified key, or a default
|
||||
/// constructed value if no such entry exists.
|
||||
ValueTy lookup(StringRef Key) const {
|
||||
const_iterator it = find(Key);
|
||||
if (it != end())
|
||||
return it->second;
|
||||
return ValueTy();
|
||||
}
|
||||
|
||||
/// Lookup the ValueTy for the \p Key, or create a default constructed value
|
||||
/// if the key is not in the map.
|
||||
ValueTy &operator[](StringRef Key) {
|
||||
return emplace_second(Key).first->second;
|
||||
}
|
||||
|
||||
/// count - Return 1 if the element is in the map, 0 otherwise.
|
||||
size_type count(StringRef Key) const {
|
||||
return find(Key) == end() ? 0 : 1;
|
||||
}
|
||||
|
||||
/// insert - Insert the specified key/value pair into the map. If the key
|
||||
/// already exists in the map, return false and ignore the request, otherwise
|
||||
/// insert it and return true.
|
||||
bool insert(MapEntryTy *KeyValue) {
|
||||
unsigned BucketNo = LookupBucketFor(KeyValue->getKey());
|
||||
StringMapEntryBase *&Bucket = TheTable[BucketNo];
|
||||
if (Bucket && Bucket != getTombstoneVal())
|
||||
return false; // Already exists in map.
|
||||
|
||||
if (Bucket == getTombstoneVal())
|
||||
--NumTombstones;
|
||||
Bucket = KeyValue;
|
||||
++NumItems;
|
||||
assert(NumItems + NumTombstones <= NumBuckets);
|
||||
|
||||
RehashTable();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// insert - Inserts the specified key/value pair into the map if the key
|
||||
/// isn't already in the map. The bool component of the returned pair is true
|
||||
/// if and only if the insertion takes place, and the iterator component of
|
||||
/// the pair points to the element with key equivalent to the key of the pair.
|
||||
std::pair<iterator, bool> insert(std::pair<StringRef, ValueTy> KV) {
|
||||
return emplace_second(KV.first, std::move(KV.second));
|
||||
}
|
||||
|
||||
/// Emplace a new element for the specified key into the map if the key isn't
|
||||
/// already in the map. The bool component of the returned pair is true
|
||||
/// if and only if the insertion takes place, and the iterator component of
|
||||
/// the pair points to the element with key equivalent to the key of the pair.
|
||||
template <typename... ArgsTy>
|
||||
std::pair<iterator, bool> emplace_second(StringRef Key, ArgsTy &&... Args) {
|
||||
unsigned BucketNo = LookupBucketFor(Key);
|
||||
StringMapEntryBase *&Bucket = TheTable[BucketNo];
|
||||
if (Bucket && Bucket != getTombstoneVal())
|
||||
return std::make_pair(iterator(TheTable + BucketNo, false),
|
||||
false); // Already exists in map.
|
||||
|
||||
if (Bucket == getTombstoneVal())
|
||||
--NumTombstones;
|
||||
Bucket = MapEntryTy::Create(Key, std::forward<ArgsTy>(Args)...);
|
||||
++NumItems;
|
||||
assert(NumItems + NumTombstones <= NumBuckets);
|
||||
|
||||
BucketNo = RehashTable(BucketNo);
|
||||
return std::make_pair(iterator(TheTable + BucketNo, false), true);
|
||||
}
|
||||
|
||||
// clear - Empties out the StringMap
|
||||
void clear() {
|
||||
if (empty()) return;
|
||||
|
||||
// Zap all values, resetting the keys back to non-present (not tombstone),
|
||||
// which is safe because we're removing all elements.
|
||||
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
|
||||
StringMapEntryBase *&Bucket = TheTable[I];
|
||||
if (Bucket && Bucket != getTombstoneVal()) {
|
||||
static_cast<MapEntryTy*>(Bucket)->Destroy();
|
||||
}
|
||||
Bucket = nullptr;
|
||||
}
|
||||
|
||||
NumItems = 0;
|
||||
NumTombstones = 0;
|
||||
}
|
||||
|
||||
/// remove - Remove the specified key/value pair from the map, but do not
|
||||
/// erase it. This aborts if the key is not in the map.
|
||||
void remove(MapEntryTy *KeyValue) {
|
||||
RemoveKey(KeyValue);
|
||||
}
|
||||
|
||||
void erase(iterator I) {
|
||||
MapEntryTy &V = *I;
|
||||
remove(&V);
|
||||
V.Destroy();
|
||||
}
|
||||
|
||||
bool erase(StringRef Key) {
|
||||
iterator I = find(Key);
|
||||
if (I == end()) return false;
|
||||
erase(I);
|
||||
return true;
|
||||
}
|
||||
|
||||
~StringMap() {
|
||||
// Delete all the elements in the map, but don't reset the elements
|
||||
// to default values. This is a copy of clear(), but avoids unnecessary
|
||||
// work not required in the destructor.
|
||||
if (!empty()) {
|
||||
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
|
||||
StringMapEntryBase *Bucket = TheTable[I];
|
||||
if (Bucket && Bucket != getTombstoneVal()) {
|
||||
static_cast<MapEntryTy*>(Bucket)->Destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
free(TheTable);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ValueTy> class StringMapConstIterator {
|
||||
protected:
|
||||
StringMapEntryBase **Ptr;
|
||||
|
||||
public:
|
||||
typedef StringMapEntry<ValueTy> value_type;
|
||||
|
||||
StringMapConstIterator() : Ptr(nullptr) { }
|
||||
|
||||
explicit StringMapConstIterator(StringMapEntryBase **Bucket,
|
||||
bool NoAdvance = false)
|
||||
: Ptr(Bucket) {
|
||||
if (!NoAdvance) AdvancePastEmptyBuckets();
|
||||
}
|
||||
|
||||
const value_type &operator*() const {
|
||||
return *static_cast<StringMapEntry<ValueTy>*>(*Ptr);
|
||||
}
|
||||
const value_type *operator->() const {
|
||||
return static_cast<StringMapEntry<ValueTy>*>(*Ptr);
|
||||
}
|
||||
|
||||
bool operator==(const StringMapConstIterator &RHS) const {
|
||||
return Ptr == RHS.Ptr;
|
||||
}
|
||||
bool operator!=(const StringMapConstIterator &RHS) const {
|
||||
return Ptr != RHS.Ptr;
|
||||
}
|
||||
|
||||
inline StringMapConstIterator& operator++() { // Preincrement
|
||||
++Ptr;
|
||||
AdvancePastEmptyBuckets();
|
||||
return *this;
|
||||
}
|
||||
StringMapConstIterator operator++(int) { // Postincrement
|
||||
StringMapConstIterator tmp = *this; ++*this; return tmp;
|
||||
}
|
||||
|
||||
private:
|
||||
void AdvancePastEmptyBuckets() {
|
||||
while (*Ptr == nullptr || *Ptr == StringMapImpl::getTombstoneVal())
|
||||
++Ptr;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ValueTy>
|
||||
class StringMapIterator : public StringMapConstIterator<ValueTy> {
|
||||
public:
|
||||
StringMapIterator() {}
|
||||
explicit StringMapIterator(StringMapEntryBase **Bucket,
|
||||
bool NoAdvance = false)
|
||||
: StringMapConstIterator<ValueTy>(Bucket, NoAdvance) {
|
||||
}
|
||||
StringMapEntry<ValueTy> &operator*() const {
|
||||
return *static_cast<StringMapEntry<ValueTy>*>(*this->Ptr);
|
||||
}
|
||||
StringMapEntry<ValueTy> *operator->() const {
|
||||
return static_cast<StringMapEntry<ValueTy>*>(*this->Ptr);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
623
src/main/native/include/llvm/StringRef.h
Normal file
623
src/main/native/include/llvm/StringRef.h
Normal file
@@ -0,0 +1,623 @@
|
||||
//===--- StringRef.h - Constant String Reference Wrapper --------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_STRINGREF_H
|
||||
#define LLVM_ADT_STRINGREF_H
|
||||
|
||||
#include "llvm/iterator_range.h"
|
||||
#include "llvm/Compiler.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
template <typename T>
|
||||
class SmallVectorImpl;
|
||||
class hash_code;
|
||||
class StringRef;
|
||||
|
||||
/// Helper functions for StringRef::getAsInteger.
|
||||
bool getAsUnsignedInteger(StringRef Str, unsigned Radix,
|
||||
unsigned long long &Result);
|
||||
|
||||
bool getAsSignedInteger(StringRef Str, unsigned Radix, long long &Result);
|
||||
|
||||
/// StringRef - Represent a constant reference to a string, i.e. a character
|
||||
/// array and a length, which need not be null terminated.
|
||||
///
|
||||
/// This class does not own the string data, it is expected to be used in
|
||||
/// situations where the character data resides in some other buffer, whose
|
||||
/// lifetime extends past that of the StringRef. For this reason, it is not in
|
||||
/// general safe to store a StringRef.
|
||||
class StringRef {
|
||||
public:
|
||||
typedef const char *iterator;
|
||||
typedef const char *const_iterator;
|
||||
static const size_t npos = ~size_t(0);
|
||||
typedef size_t size_type;
|
||||
|
||||
private:
|
||||
/// The start of the string, in an external buffer.
|
||||
const char *Data;
|
||||
|
||||
/// The length of the string.
|
||||
/// MSB of length indicates if we are null terminated or not
|
||||
/// Flag set is null terminated, flag not set is not
|
||||
size_t Length;
|
||||
|
||||
// Workaround memcmp issue with null pointers (undefined behavior)
|
||||
// by providing a specialized version
|
||||
static int compareMemory(const char *Lhs, const char *Rhs, size_t Length) {
|
||||
if (Length == 0) { return 0; }
|
||||
return ::memcmp(Lhs,Rhs,Length);
|
||||
}
|
||||
|
||||
/// Set the flag to say we are null terminated
|
||||
void set_null_terminated(bool set) {
|
||||
if (set)
|
||||
Length |= ((size_t)1 << (sizeof(size_t) * 8 - 1));
|
||||
else {
|
||||
Length &= ~((size_t)1 << (sizeof(size_t) * 8 - 1));
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/// @name Constructors
|
||||
/// @{
|
||||
|
||||
/// Construct an empty string ref.
|
||||
/*implicit*/ StringRef() : Data(nullptr), Length(0) {}
|
||||
|
||||
/// Construct a string ref from a cstring.
|
||||
/*implicit*/ StringRef(const char *Str)
|
||||
: Data(Str) {
|
||||
assert(Str && "StringRef cannot be built from a NULL argument");
|
||||
Length = ::strlen(Str); // invoking strlen(NULL) is undefined behavior
|
||||
// Require length to not use MSB of size
|
||||
assert(Length < ~((size_t)1 << (sizeof(size_t) * 8 - 1)));
|
||||
// If from a const char*, we are null terminated
|
||||
set_null_terminated(true);
|
||||
}
|
||||
|
||||
/// Construct a string ref from a pointer and length.
|
||||
/*implicit*/ StringRef(const char *data, size_t length)
|
||||
: Data(data), Length(length) {
|
||||
assert((data || length == 0) &&
|
||||
"StringRef cannot be built from a NULL argument with non-null length");
|
||||
// Require length to not use MSB of size
|
||||
assert(Length < ~((size_t)1 << (sizeof(size_t) * 8 - 1)));
|
||||
// If passed an explicit length, we are not null terminated
|
||||
set_null_terminated(false);
|
||||
}
|
||||
|
||||
/// Construct a string ref from an std::string.
|
||||
/*implicit*/ StringRef(const std::string &Str)
|
||||
: Data(Str.data()), Length(Str.length()) {
|
||||
// Require length to not use MSB of size
|
||||
assert(Length < ~((size_t)1 << (sizeof(size_t) * 8 - 1)));
|
||||
// If from a std::string, we are null terminated
|
||||
set_null_terminated(true);
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Iterators
|
||||
/// @{
|
||||
|
||||
iterator begin() const { return Data; }
|
||||
|
||||
iterator end() const { return Data + size(); }
|
||||
|
||||
const unsigned char *bytes_begin() const {
|
||||
return reinterpret_cast<const unsigned char *>(begin());
|
||||
}
|
||||
const unsigned char *bytes_end() const {
|
||||
return reinterpret_cast<const unsigned char *>(end());
|
||||
}
|
||||
iterator_range<const unsigned char *> bytes() const {
|
||||
return make_range(bytes_begin(), bytes_end());
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name String Operations
|
||||
/// @{
|
||||
|
||||
/// data - Get a pointer to the start of the string (which may not be null
|
||||
/// terminated).
|
||||
const char *data() const { return Data; }
|
||||
|
||||
/// c_str - Get a null terminated pointer to the start of the string
|
||||
/// If string is not null terminated, use buffer to store new string
|
||||
const char *c_str(llvm::SmallVectorImpl<char>& buf) const;
|
||||
|
||||
/// empty - Check if the string is empty.
|
||||
bool empty() const { return size() == 0; }
|
||||
|
||||
/// size - Get the string size.
|
||||
size_t size() const {
|
||||
return Length & ~((size_t)1 << (sizeof(size_t) * 8 - 1));
|
||||
}
|
||||
|
||||
/// is_null_terminated - Get if the string is guaranteed null terminated
|
||||
bool is_null_terminated() const {
|
||||
return (Length & ((size_t)1 << (sizeof(size_t) * 8 - 1))) ==
|
||||
((size_t)1 << (sizeof(size_t) * 8 - 1));
|
||||
}
|
||||
|
||||
/// front - Get the first character in the string.
|
||||
char front() const {
|
||||
assert(!empty());
|
||||
return Data[0];
|
||||
}
|
||||
|
||||
/// back - Get the last character in the string.
|
||||
char back() const {
|
||||
assert(!empty());
|
||||
return Data[size()-1];
|
||||
}
|
||||
|
||||
// copy - Allocate copy in Allocator and return StringRef to it.
|
||||
template <typename Allocator> StringRef copy(Allocator &A) const {
|
||||
// Don't request a length 0 copy from the allocator.
|
||||
if (empty())
|
||||
return StringRef();
|
||||
char *S = A.template Allocate<char>(size());
|
||||
std::copy(begin(), end(), S);
|
||||
return StringRef(S, size());
|
||||
}
|
||||
|
||||
/// equals - Check for string equality, this is more efficient than
|
||||
/// compare() when the relative ordering of inequal strings isn't needed.
|
||||
bool equals(StringRef RHS) const {
|
||||
return (size() == RHS.size() &&
|
||||
compareMemory(Data, RHS.Data, RHS.size()) == 0);
|
||||
}
|
||||
|
||||
/// equals_lower - Check for string equality, ignoring case.
|
||||
bool equals_lower(StringRef RHS) const {
|
||||
return size() == RHS.size() && compare_lower(RHS) == 0;
|
||||
}
|
||||
|
||||
/// compare - Compare two strings; the result is -1, 0, or 1 if this string
|
||||
/// is lexicographically less than, equal to, or greater than the \p RHS.
|
||||
int compare(StringRef RHS) const {
|
||||
// Check the prefix for a mismatch.
|
||||
if (int Res = compareMemory(Data, RHS.Data, std::min(size(), RHS.size())))
|
||||
return Res < 0 ? -1 : 1;
|
||||
|
||||
// Otherwise the prefixes match, so we only need to check the lengths.
|
||||
if (size() == RHS.size())
|
||||
return 0;
|
||||
return size() < RHS.size() ? -1 : 1;
|
||||
}
|
||||
|
||||
/// compare_lower - Compare two strings, ignoring case.
|
||||
int compare_lower(StringRef RHS) const;
|
||||
|
||||
/// compare_numeric - Compare two strings, treating sequences of digits as
|
||||
/// numbers.
|
||||
int compare_numeric(StringRef RHS) const;
|
||||
|
||||
/// str - Get the contents as an std::string.
|
||||
std::string str() const {
|
||||
if (!Data) return std::string();
|
||||
return std::string(Data, size());
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Operator Overloads
|
||||
/// @{
|
||||
|
||||
char operator[](size_t Index) const {
|
||||
assert(Index < size() && "Invalid index!");
|
||||
return Data[Index];
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Type Conversions
|
||||
/// @{
|
||||
|
||||
operator std::string() const {
|
||||
return str();
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name String Predicates
|
||||
/// @{
|
||||
|
||||
/// Check if this string starts with the given \p Prefix.
|
||||
bool startswith(StringRef Prefix) const {
|
||||
return size() >= Prefix.size() &&
|
||||
compareMemory(Data, Prefix.Data, Prefix.size()) == 0;
|
||||
}
|
||||
|
||||
/// Check if this string starts with the given \p Prefix, ignoring case.
|
||||
bool startswith_lower(StringRef Prefix) const;
|
||||
|
||||
/// Check if this string ends with the given \p Suffix.
|
||||
bool endswith(StringRef Suffix) const {
|
||||
return size() >= Suffix.size() &&
|
||||
compareMemory(end() - Suffix.size(), Suffix.Data, Suffix.size()) == 0;
|
||||
}
|
||||
|
||||
/// Check if this string ends with the given \p Suffix, ignoring case.
|
||||
bool endswith_lower(StringRef Suffix) const;
|
||||
|
||||
/// @}
|
||||
/// @name String Searching
|
||||
/// @{
|
||||
|
||||
/// Search for the first character \p C in the string.
|
||||
///
|
||||
/// \returns The index of the first occurrence of \p C, or npos if not
|
||||
/// found.
|
||||
size_t find(char C, size_t From = 0) const {
|
||||
size_t FindBegin = std::min(From, size());
|
||||
if (FindBegin < size()) { // Avoid calling memchr with nullptr.
|
||||
// Just forward to memchr, which is faster than a hand-rolled loop.
|
||||
if (const void *P = ::memchr(Data + FindBegin, C, size() - FindBegin))
|
||||
return static_cast<const char *>(P) - Data;
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
/// Search for the first string \p Str in the string.
|
||||
///
|
||||
/// \returns The index of the first occurrence of \p Str, or npos if not
|
||||
/// found.
|
||||
size_t find(StringRef Str, size_t From = 0) const;
|
||||
|
||||
/// Search for the last character \p C in the string.
|
||||
///
|
||||
/// \returns The index of the last occurrence of \p C, or npos if not
|
||||
/// found.
|
||||
size_t rfind(char C, size_t From = npos) const {
|
||||
From = std::min(From, size());
|
||||
size_t i = From;
|
||||
while (i != 0) {
|
||||
--i;
|
||||
if (Data[i] == C)
|
||||
return i;
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
/// Search for the last string \p Str in the string.
|
||||
///
|
||||
/// \returns The index of the last occurrence of \p Str, or npos if not
|
||||
/// found.
|
||||
size_t rfind(StringRef Str) const;
|
||||
|
||||
/// Find the first character in the string that is \p C, or npos if not
|
||||
/// found. Same as find.
|
||||
size_t find_first_of(char C, size_t From = 0) const {
|
||||
return find(C, From);
|
||||
}
|
||||
|
||||
/// Find the first character in the string that is in \p Chars, or npos if
|
||||
/// not found.
|
||||
///
|
||||
/// Complexity: O(size() + Chars.size())
|
||||
size_t find_first_of(StringRef Chars, size_t From = 0) const;
|
||||
|
||||
/// Find the first character in the string that is not \p C or npos if not
|
||||
/// found.
|
||||
size_t find_first_not_of(char C, size_t From = 0) const;
|
||||
|
||||
/// Find the first character in the string that is not in the string
|
||||
/// \p Chars, or npos if not found.
|
||||
///
|
||||
/// Complexity: O(size() + Chars.size())
|
||||
size_t find_first_not_of(StringRef Chars, size_t From = 0) const;
|
||||
|
||||
/// Find the last character in the string that is \p C, or npos if not
|
||||
/// found.
|
||||
size_t find_last_of(char C, size_t From = npos) const {
|
||||
return rfind(C, From);
|
||||
}
|
||||
|
||||
/// Find the last character in the string that is in \p C, or npos if not
|
||||
/// found.
|
||||
///
|
||||
/// Complexity: O(size() + Chars.size())
|
||||
size_t find_last_of(StringRef Chars, size_t From = npos) const;
|
||||
|
||||
/// Find the last character in the string that is not \p C, or npos if not
|
||||
/// found.
|
||||
size_t find_last_not_of(char C, size_t From = npos) const;
|
||||
|
||||
/// Find the last character in the string that is not in \p Chars, or
|
||||
/// npos if not found.
|
||||
///
|
||||
/// Complexity: O(size() + Chars.size())
|
||||
size_t find_last_not_of(StringRef Chars, size_t From = npos) const;
|
||||
|
||||
/// @}
|
||||
/// @name Helpful Algorithms
|
||||
/// @{
|
||||
|
||||
/// Return the number of occurrences of \p C in the string.
|
||||
size_t count(char C) const {
|
||||
size_t Count = 0;
|
||||
for (size_t i = 0, e = size(); i != e; ++i)
|
||||
if (Data[i] == C)
|
||||
++Count;
|
||||
return Count;
|
||||
}
|
||||
|
||||
/// Return the number of non-overlapped occurrences of \p Str in
|
||||
/// the string.
|
||||
size_t count(StringRef Str) const;
|
||||
|
||||
/// Parse the current string as an integer of the specified radix. If
|
||||
/// \p Radix is specified as zero, this does radix autosensing using
|
||||
/// extended C rules: 0 is octal, 0x is hex, 0b is binary.
|
||||
///
|
||||
/// If the string is invalid or if only a subset of the string is valid,
|
||||
/// this returns true to signify the error. The string is considered
|
||||
/// erroneous if empty or if it overflows T.
|
||||
template <typename T>
|
||||
typename std::enable_if<std::numeric_limits<T>::is_signed, bool>::type
|
||||
getAsInteger(unsigned Radix, T &Result) const {
|
||||
long long LLVal;
|
||||
if (getAsSignedInteger(*this, Radix, LLVal) ||
|
||||
static_cast<T>(LLVal) != LLVal)
|
||||
return true;
|
||||
Result = LLVal;
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<!std::numeric_limits<T>::is_signed, bool>::type
|
||||
getAsInteger(unsigned Radix, T &Result) const {
|
||||
unsigned long long ULLVal;
|
||||
// The additional cast to unsigned long long is required to avoid the
|
||||
// Visual C++ warning C4805: '!=' : unsafe mix of type 'bool' and type
|
||||
// 'unsigned __int64' when instantiating getAsInteger with T = bool.
|
||||
if (getAsUnsignedInteger(*this, Radix, ULLVal) ||
|
||||
static_cast<unsigned long long>(static_cast<T>(ULLVal)) != ULLVal)
|
||||
return true;
|
||||
Result = ULLVal;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name String Operations
|
||||
/// @{
|
||||
|
||||
// Convert the given ASCII string to lowercase.
|
||||
std::string lower() const;
|
||||
|
||||
/// Convert the given ASCII string to uppercase.
|
||||
std::string upper() const;
|
||||
|
||||
/// @}
|
||||
/// @name Substring Operations
|
||||
/// @{
|
||||
|
||||
/// Return a reference to the substring from [Start, Start + N).
|
||||
///
|
||||
/// \param Start The index of the starting character in the substring; if
|
||||
/// the index is npos or greater than the length of the string then the
|
||||
/// empty substring will be returned.
|
||||
///
|
||||
/// \param N The number of characters to included in the substring. If N
|
||||
/// exceeds the number of characters remaining in the string, the string
|
||||
/// suffix (starting with \p Start) will be returned.
|
||||
StringRef substr(size_t Start, size_t N = npos) const {
|
||||
Start = std::min(Start, size());
|
||||
return StringRef(Data + Start, std::min(N, size() - Start));
|
||||
}
|
||||
|
||||
/// Return a StringRef equal to 'this' but with the first \p N elements
|
||||
/// dropped.
|
||||
StringRef drop_front(size_t N = 1) const {
|
||||
assert(size() >= N && "Dropping more elements than exist");
|
||||
return substr(N);
|
||||
}
|
||||
|
||||
/// Return a StringRef equal to 'this' but with the last \p N elements
|
||||
/// dropped.
|
||||
StringRef drop_back(size_t N = 1) const {
|
||||
assert(size() >= N && "Dropping more elements than exist");
|
||||
return substr(0, size()-N);
|
||||
}
|
||||
|
||||
/// Return a reference to the substring from [Start, End).
|
||||
///
|
||||
/// \param Start The index of the starting character in the substring; if
|
||||
/// the index is npos or greater than the length of the string then the
|
||||
/// empty substring will be returned.
|
||||
///
|
||||
/// \param End The index following the last character to include in the
|
||||
/// substring. If this is npos or exceeds the number of characters
|
||||
/// remaining in the string, the string suffix (starting with \p Start)
|
||||
/// will be returned. If this is less than \p Start, an empty string will
|
||||
/// be returned.
|
||||
StringRef slice(size_t Start, size_t End) const {
|
||||
Start = std::min(Start, size());
|
||||
End = std::min(std::max(Start, End), size());
|
||||
return StringRef(Data + Start, End - Start);
|
||||
}
|
||||
|
||||
/// Split into two substrings around the first occurrence of a separator
|
||||
/// character.
|
||||
///
|
||||
/// If \p Separator is in the string, then the result is a pair (LHS, RHS)
|
||||
/// such that (*this == LHS + Separator + RHS) is true and RHS is
|
||||
/// maximal. If \p Separator is not in the string, then the result is a
|
||||
/// pair (LHS, RHS) where (*this == LHS) and (RHS == "").
|
||||
///
|
||||
/// \param Separator The character to split on.
|
||||
/// \returns The split substrings.
|
||||
std::pair<StringRef, StringRef> split(char Separator) const {
|
||||
size_t Idx = find(Separator);
|
||||
if (Idx == npos)
|
||||
return std::make_pair(*this, StringRef());
|
||||
return std::make_pair(slice(0, Idx), slice(Idx+1, npos));
|
||||
}
|
||||
|
||||
/// Split into two substrings around the first occurrence of a separator
|
||||
/// string.
|
||||
///
|
||||
/// If \p Separator is in the string, then the result is a pair (LHS, RHS)
|
||||
/// such that (*this == LHS + Separator + RHS) is true and RHS is
|
||||
/// maximal. If \p Separator is not in the string, then the result is a
|
||||
/// pair (LHS, RHS) where (*this == LHS) and (RHS == "").
|
||||
///
|
||||
/// \param Separator - The string to split on.
|
||||
/// \return - The split substrings.
|
||||
std::pair<StringRef, StringRef> split(StringRef Separator) const {
|
||||
size_t Idx = find(Separator);
|
||||
if (Idx == npos)
|
||||
return std::make_pair(*this, StringRef());
|
||||
return std::make_pair(slice(0, Idx), slice(Idx + Separator.size(), npos));
|
||||
}
|
||||
|
||||
/// Split into substrings around the occurrences of a separator string.
|
||||
///
|
||||
/// Each substring is stored in \p A. If \p MaxSplit is >= 0, at most
|
||||
/// \p MaxSplit splits are done and consequently <= \p MaxSplit + 1
|
||||
/// elements are added to A.
|
||||
/// If \p KeepEmpty is false, empty strings are not added to \p A. They
|
||||
/// still count when considering \p MaxSplit
|
||||
/// An useful invariant is that
|
||||
/// Separator.join(A) == *this if MaxSplit == -1 and KeepEmpty == true
|
||||
///
|
||||
/// \param A - Where to put the substrings.
|
||||
/// \param Separator - The string to split on.
|
||||
/// \param MaxSplit - The maximum number of times the string is split.
|
||||
/// \param KeepEmpty - True if empty substring should be added.
|
||||
void split(SmallVectorImpl<StringRef> &A,
|
||||
StringRef Separator, int MaxSplit = -1,
|
||||
bool KeepEmpty = true) const;
|
||||
|
||||
/// Split into substrings around the occurrences of a separator character.
|
||||
///
|
||||
/// Each substring is stored in \p A. If \p MaxSplit is >= 0, at most
|
||||
/// \p MaxSplit splits are done and consequently <= \p MaxSplit + 1
|
||||
/// elements are added to A.
|
||||
/// If \p KeepEmpty is false, empty strings are not added to \p A. They
|
||||
/// still count when considering \p MaxSplit
|
||||
/// An useful invariant is that
|
||||
/// Separator.join(A) == *this if MaxSplit == -1 and KeepEmpty == true
|
||||
///
|
||||
/// \param A - Where to put the substrings.
|
||||
/// \param Separator - The string to split on.
|
||||
/// \param MaxSplit - The maximum number of times the string is split.
|
||||
/// \param KeepEmpty - True if empty substring should be added.
|
||||
void split(SmallVectorImpl<StringRef> &A, char Separator, int MaxSplit = -1,
|
||||
bool KeepEmpty = true) const;
|
||||
|
||||
/// Split into two substrings around the last occurrence of a separator
|
||||
/// character.
|
||||
///
|
||||
/// If \p Separator is in the string, then the result is a pair (LHS, RHS)
|
||||
/// such that (*this == LHS + Separator + RHS) is true and RHS is
|
||||
/// minimal. If \p Separator is not in the string, then the result is a
|
||||
/// pair (LHS, RHS) where (*this == LHS) and (RHS == "").
|
||||
///
|
||||
/// \param Separator - The character to split on.
|
||||
/// \return - The split substrings.
|
||||
std::pair<StringRef, StringRef> rsplit(char Separator) const {
|
||||
size_t Idx = rfind(Separator);
|
||||
if (Idx == npos)
|
||||
return std::make_pair(*this, StringRef());
|
||||
return std::make_pair(slice(0, Idx), slice(Idx+1, npos));
|
||||
}
|
||||
|
||||
/// Return string with consecutive \p Char characters starting from the
|
||||
/// the left removed.
|
||||
StringRef ltrim(char Char) const {
|
||||
return drop_front(std::min(size(), find_first_not_of(Char)));
|
||||
}
|
||||
|
||||
/// Return string with consecutive characters in \p Chars starting from
|
||||
/// the left removed.
|
||||
StringRef ltrim(StringRef Chars = " \t\n\v\f\r") const {
|
||||
return drop_front(std::min(size(), find_first_not_of(Chars)));
|
||||
}
|
||||
|
||||
/// Return string with consecutive \p Char characters starting from the
|
||||
/// right removed.
|
||||
StringRef rtrim(char Char) const {
|
||||
return drop_back(size() - std::min(size(), find_last_not_of(Char) + 1));
|
||||
}
|
||||
|
||||
/// Return string with consecutive characters in \p Chars starting from
|
||||
/// the right removed.
|
||||
StringRef rtrim(StringRef Chars = " \t\n\v\f\r") const {
|
||||
return drop_back(size() - std::min(size(), find_last_not_of(Chars) + 1));
|
||||
}
|
||||
|
||||
/// Return string with consecutive \p Char characters starting from the
|
||||
/// left and right removed.
|
||||
StringRef trim(char Char) const {
|
||||
return ltrim(Char).rtrim(Char);
|
||||
}
|
||||
|
||||
/// Return string with consecutive characters in \p Chars starting from
|
||||
/// the left and right removed.
|
||||
StringRef trim(StringRef Chars = " \t\n\v\f\r") const {
|
||||
return ltrim(Chars).rtrim(Chars);
|
||||
}
|
||||
|
||||
/// @}
|
||||
};
|
||||
|
||||
/// @name StringRef Comparison Operators
|
||||
/// @{
|
||||
|
||||
inline bool operator==(StringRef LHS, StringRef RHS) {
|
||||
return LHS.equals(RHS);
|
||||
}
|
||||
|
||||
inline bool operator!=(StringRef LHS, StringRef RHS) {
|
||||
return !(LHS == RHS);
|
||||
}
|
||||
|
||||
inline bool operator<(StringRef LHS, StringRef RHS) {
|
||||
return LHS.compare(RHS) == -1;
|
||||
}
|
||||
|
||||
inline bool operator<=(StringRef LHS, StringRef RHS) {
|
||||
return LHS.compare(RHS) != 1;
|
||||
}
|
||||
|
||||
inline bool operator>(StringRef LHS, StringRef RHS) {
|
||||
return LHS.compare(RHS) == 1;
|
||||
}
|
||||
|
||||
inline bool operator>=(StringRef LHS, StringRef RHS) {
|
||||
return LHS.compare(RHS) != -1;
|
||||
}
|
||||
|
||||
inline std::string &operator+=(std::string &buffer, StringRef string) {
|
||||
return buffer.append(string.data(), string.size());
|
||||
}
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &os, StringRef string) {
|
||||
os.write(string.data(), string.size());
|
||||
return os;
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// \brief Compute a hash_code for a StringRef.
|
||||
hash_code hash_value(StringRef S);
|
||||
|
||||
// StringRefs can be treated like a POD type.
|
||||
template <typename T> struct isPodLike;
|
||||
template <> struct isPodLike<StringRef> { static const bool value = true; };
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
19
src/main/native/include/llvm/WindowsError.h
Normal file
19
src/main/native/include/llvm/WindowsError.h
Normal file
@@ -0,0 +1,19 @@
|
||||
//===-- WindowsError.h - Support for mapping windows errors to posix-------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_WINDOWSERROR_H
|
||||
#define LLVM_SUPPORT_WINDOWSERROR_H
|
||||
|
||||
#include <system_error>
|
||||
|
||||
namespace llvm {
|
||||
std::error_code mapWindowsError(unsigned EV);
|
||||
}
|
||||
|
||||
#endif
|
||||
68
src/main/native/include/llvm/iterator_range.h
Normal file
68
src/main/native/include/llvm/iterator_range.h
Normal file
@@ -0,0 +1,68 @@
|
||||
//===- iterator_range.h - A range adaptor for iterators ---------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// This provides a very simple, boring adaptor for a begin and end iterator
|
||||
/// into a range type. This should be used to build range views that work well
|
||||
/// with range based for loops and range based constructors.
|
||||
///
|
||||
/// Note that code here follows more standards-based coding conventions as it
|
||||
/// is mirroring proposed interfaces for standardization.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_ITERATOR_RANGE_H
|
||||
#define LLVM_ADT_ITERATOR_RANGE_H
|
||||
|
||||
#include <utility>
|
||||
#include <iterator>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// \brief A range adaptor for a pair of iterators.
|
||||
///
|
||||
/// This just wraps two iterators into a range-compatible interface. Nothing
|
||||
/// fancy at all.
|
||||
template <typename IteratorT>
|
||||
class iterator_range {
|
||||
IteratorT begin_iterator, end_iterator;
|
||||
|
||||
public:
|
||||
//TODO: Add SFINAE to test that the Container's iterators match the range's
|
||||
// iterators.
|
||||
template <typename Container>
|
||||
iterator_range(Container &&c)
|
||||
//TODO: Consider ADL/non-member begin/end calls.
|
||||
: begin_iterator(c.begin()), end_iterator(c.end()) {}
|
||||
iterator_range(IteratorT begin_iterator, IteratorT end_iterator)
|
||||
: begin_iterator(std::move(begin_iterator)),
|
||||
end_iterator(std::move(end_iterator)) {}
|
||||
|
||||
IteratorT begin() const { return begin_iterator; }
|
||||
IteratorT end() const { return end_iterator; }
|
||||
};
|
||||
|
||||
/// \brief Convenience function for iterating over sub-ranges.
|
||||
///
|
||||
/// This provides a bit of syntactic sugar to make using sub-ranges
|
||||
/// in for loops a bit easier. Analogous to std::make_pair().
|
||||
template <class T> iterator_range<T> make_range(T x, T y) {
|
||||
return iterator_range<T>(std::move(x), std::move(y));
|
||||
}
|
||||
|
||||
template <typename T> iterator_range<T> make_range(std::pair<T, T> p) {
|
||||
return iterator_range<T>(std::move(p.first), std::move(p.second));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
iterator_range<decltype(begin(std::declval<T>()))> drop_begin(T &&t, int n) {
|
||||
return make_range(std::next(begin(t), n), end(t));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
42
src/main/native/include/llvm/raw_os_ostream.h
Normal file
42
src/main/native/include/llvm/raw_os_ostream.h
Normal file
@@ -0,0 +1,42 @@
|
||||
//===- raw_os_ostream.h - std::ostream adaptor for raw_ostream --*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the raw_os_ostream class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_RAW_OS_OSTREAM_H
|
||||
#define LLVM_SUPPORT_RAW_OS_OSTREAM_H
|
||||
|
||||
#include "llvm/raw_ostream.h"
|
||||
#include <iosfwd>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// raw_os_ostream - A raw_ostream that writes to an std::ostream. This is a
|
||||
/// simple adaptor class. It does not check for output errors; clients should
|
||||
/// use the underlying stream to detect errors.
|
||||
class raw_os_ostream : public raw_ostream {
|
||||
std::ostream &OS;
|
||||
|
||||
/// write_impl - See raw_ostream::write_impl.
|
||||
void write_impl(const char *Ptr, size_t Size) override;
|
||||
|
||||
/// current_pos - Return the current position within the stream, not
|
||||
/// counting the bytes currently in the buffer.
|
||||
uint64_t current_pos() const override;
|
||||
|
||||
public:
|
||||
raw_os_ostream(std::ostream &O) : OS(O) {}
|
||||
~raw_os_ostream() override;
|
||||
};
|
||||
|
||||
} // end llvm namespace
|
||||
|
||||
#endif
|
||||
547
src/main/native/include/llvm/raw_ostream.h
Normal file
547
src/main/native/include/llvm/raw_ostream.h
Normal file
@@ -0,0 +1,547 @@
|
||||
//===--- raw_ostream.h - Raw output stream ----------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the raw_ostream class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_RAW_OSTREAM_H
|
||||
#define LLVM_SUPPORT_RAW_OSTREAM_H
|
||||
|
||||
#include "llvm/SmallVector.h"
|
||||
#include "llvm/StringRef.h"
|
||||
#include <cstdint>
|
||||
#include <system_error>
|
||||
|
||||
namespace llvm {
|
||||
class format_object_base;
|
||||
class FormattedString;
|
||||
class FormattedNumber;
|
||||
template <typename T> class SmallVectorImpl;
|
||||
|
||||
namespace sys {
|
||||
namespace fs {
|
||||
enum OpenFlags : unsigned {
|
||||
F_None = 0,
|
||||
|
||||
/// F_Excl - When opening a file, this flag makes raw_fd_ostream
|
||||
/// report an error if the file already exists.
|
||||
F_Excl = 1,
|
||||
|
||||
/// F_Append - When opening a file, if it already exists append to the
|
||||
/// existing file instead of returning an error. This may not be specified
|
||||
/// with F_Excl.
|
||||
F_Append = 2,
|
||||
|
||||
/// The file should be opened in text mode on platforms that make this
|
||||
/// distinction.
|
||||
F_Text = 4,
|
||||
|
||||
/// Open the file for read and write.
|
||||
F_RW = 8
|
||||
};
|
||||
|
||||
inline OpenFlags operator|(OpenFlags A, OpenFlags B) {
|
||||
return OpenFlags(unsigned(A) | unsigned(B));
|
||||
}
|
||||
|
||||
inline OpenFlags &operator|=(OpenFlags &A, OpenFlags B) {
|
||||
A = A | B;
|
||||
return A;
|
||||
}
|
||||
} // namespace fs
|
||||
} // namespace sys
|
||||
|
||||
/// This class implements an extremely fast bulk output stream that can *only*
|
||||
/// output to a stream. It does not support seeking, reopening, rewinding, line
|
||||
/// buffered disciplines etc. It is a simple buffer that outputs
|
||||
/// a chunk at a time.
|
||||
class raw_ostream {
|
||||
private:
|
||||
void operator=(const raw_ostream &) = delete;
|
||||
raw_ostream(const raw_ostream &) = delete;
|
||||
|
||||
/// The buffer is handled in such a way that the buffer is
|
||||
/// uninitialized, unbuffered, or out of space when OutBufCur >=
|
||||
/// OutBufEnd. Thus a single comparison suffices to determine if we
|
||||
/// need to take the slow path to write a single character.
|
||||
///
|
||||
/// The buffer is in one of three states:
|
||||
/// 1. Unbuffered (BufferMode == Unbuffered)
|
||||
/// 1. Uninitialized (BufferMode != Unbuffered && OutBufStart == 0).
|
||||
/// 2. Buffered (BufferMode != Unbuffered && OutBufStart != 0 &&
|
||||
/// OutBufEnd - OutBufStart >= 1).
|
||||
///
|
||||
/// If buffered, then the raw_ostream owns the buffer if (BufferMode ==
|
||||
/// InternalBuffer); otherwise the buffer has been set via SetBuffer and is
|
||||
/// managed by the subclass.
|
||||
///
|
||||
/// If a subclass installs an external buffer using SetBuffer then it can wait
|
||||
/// for a \see write_impl() call to handle the data which has been put into
|
||||
/// this buffer.
|
||||
char *OutBufStart, *OutBufEnd, *OutBufCur;
|
||||
|
||||
enum BufferKind {
|
||||
Unbuffered = 0,
|
||||
InternalBuffer,
|
||||
ExternalBuffer
|
||||
} BufferMode;
|
||||
|
||||
public:
|
||||
// color order matches ANSI escape sequence, don't change
|
||||
enum Colors {
|
||||
BLACK=0,
|
||||
RED,
|
||||
GREEN,
|
||||
YELLOW,
|
||||
BLUE,
|
||||
MAGENTA,
|
||||
CYAN,
|
||||
WHITE,
|
||||
SAVEDCOLOR
|
||||
};
|
||||
|
||||
explicit raw_ostream(bool unbuffered = false)
|
||||
: BufferMode(unbuffered ? Unbuffered : InternalBuffer) {
|
||||
// Start out ready to flush.
|
||||
OutBufStart = OutBufEnd = OutBufCur = nullptr;
|
||||
}
|
||||
|
||||
virtual ~raw_ostream();
|
||||
|
||||
/// tell - Return the current offset with the file.
|
||||
uint64_t tell() const { return current_pos() + GetNumBytesInBuffer(); }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Configuration Interface
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// Set the stream to be buffered, with an automatically determined buffer
|
||||
/// size.
|
||||
void SetBuffered();
|
||||
|
||||
/// Set the stream to be buffered, using the specified buffer size.
|
||||
void SetBufferSize(size_t Size) {
|
||||
flush();
|
||||
SetBufferAndMode(new char[Size], Size, InternalBuffer);
|
||||
}
|
||||
|
||||
size_t GetBufferSize() const {
|
||||
// If we're supposed to be buffered but haven't actually gotten around
|
||||
// to allocating the buffer yet, return the value that would be used.
|
||||
if (BufferMode != Unbuffered && OutBufStart == nullptr)
|
||||
return preferred_buffer_size();
|
||||
|
||||
// Otherwise just return the size of the allocated buffer.
|
||||
return OutBufEnd - OutBufStart;
|
||||
}
|
||||
|
||||
/// Set the stream to be unbuffered. When unbuffered, the stream will flush
|
||||
/// after every write. This routine will also flush the buffer immediately
|
||||
/// when the stream is being set to unbuffered.
|
||||
void SetUnbuffered() {
|
||||
flush();
|
||||
SetBufferAndMode(nullptr, 0, Unbuffered);
|
||||
}
|
||||
|
||||
size_t GetNumBytesInBuffer() const {
|
||||
return OutBufCur - OutBufStart;
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Data Output Interface
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
void flush() {
|
||||
if (OutBufCur != OutBufStart)
|
||||
flush_nonempty();
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(char C) {
|
||||
if (OutBufCur >= OutBufEnd)
|
||||
return write(C);
|
||||
*OutBufCur++ = C;
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(unsigned char C) {
|
||||
if (OutBufCur >= OutBufEnd)
|
||||
return write(C);
|
||||
*OutBufCur++ = C;
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(signed char C) {
|
||||
if (OutBufCur >= OutBufEnd)
|
||||
return write(C);
|
||||
*OutBufCur++ = C;
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(StringRef Str) {
|
||||
// Inline fast path, particularly for strings with a known length.
|
||||
size_t Size = Str.size();
|
||||
|
||||
// Make sure we can use the fast path.
|
||||
if (Size > (size_t)(OutBufEnd - OutBufCur))
|
||||
return write(Str.data(), Size);
|
||||
|
||||
if (Size) {
|
||||
memcpy(OutBufCur, Str.data(), Size);
|
||||
OutBufCur += Size;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(const char *Str) {
|
||||
// Inline fast path, particularly for constant strings where a sufficiently
|
||||
// smart compiler will simplify strlen.
|
||||
|
||||
return this->operator<<(StringRef(Str));
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(const std::string &Str) {
|
||||
// Avoid the fast path, it would only increase code size for a marginal win.
|
||||
return write(Str.data(), Str.length());
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(const llvm::SmallVectorImpl<char> &Str) {
|
||||
return write(Str.data(), Str.size());
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(unsigned long N);
|
||||
raw_ostream &operator<<(long N);
|
||||
raw_ostream &operator<<(unsigned long long N);
|
||||
raw_ostream &operator<<(long long N);
|
||||
raw_ostream &operator<<(const void *P);
|
||||
raw_ostream &operator<<(unsigned int N) {
|
||||
return this->operator<<(static_cast<unsigned long>(N));
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(int N) {
|
||||
return this->operator<<(static_cast<long>(N));
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(double N);
|
||||
|
||||
/// Output \p N in hexadecimal, without any prefix or padding.
|
||||
raw_ostream &write_hex(unsigned long long N);
|
||||
|
||||
/// Output \p Str, turning '\\', '\t', '\n', '"', and anything that doesn't
|
||||
/// satisfy std::isprint into an escape sequence.
|
||||
raw_ostream &write_escaped(StringRef Str, bool UseHexEscapes = false);
|
||||
|
||||
raw_ostream &write(unsigned char C);
|
||||
raw_ostream &write(const char *Ptr, size_t Size);
|
||||
|
||||
// Formatted output, see the format() function in Support/Format.h.
|
||||
raw_ostream &operator<<(const format_object_base &Fmt);
|
||||
|
||||
// Formatted output, see the leftJustify() function in Support/Format.h.
|
||||
raw_ostream &operator<<(const FormattedString &);
|
||||
|
||||
// Formatted output, see the formatHex() function in Support/Format.h.
|
||||
raw_ostream &operator<<(const FormattedNumber &);
|
||||
|
||||
/// indent - Insert 'NumSpaces' spaces.
|
||||
raw_ostream &indent(unsigned NumSpaces);
|
||||
|
||||
/// Changes the foreground color of text that will be output from this point
|
||||
/// forward.
|
||||
/// @param Color ANSI color to use, the special SAVEDCOLOR can be used to
|
||||
/// change only the bold attribute, and keep colors untouched
|
||||
/// @param Bold bold/brighter text, default false
|
||||
/// @param BG if true change the background, default: change foreground
|
||||
/// @returns itself so it can be used within << invocations
|
||||
virtual raw_ostream &changeColor(enum Colors Color,
|
||||
bool Bold = false,
|
||||
bool BG = false) {
|
||||
(void)Color;
|
||||
(void)Bold;
|
||||
(void)BG;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Resets the colors to terminal defaults. Call this when you are done
|
||||
/// outputting colored text, or before program exit.
|
||||
virtual raw_ostream &resetColor() { return *this; }
|
||||
|
||||
/// Reverses the foreground and background colors.
|
||||
virtual raw_ostream &reverseColor() { return *this; }
|
||||
|
||||
/// This function determines if this stream is connected to a "tty" or
|
||||
/// "console" window. That is, the output would be displayed to the user
|
||||
/// rather than being put on a pipe or stored in a file.
|
||||
virtual bool is_displayed() const { return false; }
|
||||
|
||||
/// This function determines if this stream is displayed and supports colors.
|
||||
virtual bool has_colors() const { return is_displayed(); }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Subclass Interface
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
private:
|
||||
/// The is the piece of the class that is implemented by subclasses. This
|
||||
/// writes the \p Size bytes starting at
|
||||
/// \p Ptr to the underlying stream.
|
||||
///
|
||||
/// This function is guaranteed to only be called at a point at which it is
|
||||
/// safe for the subclass to install a new buffer via SetBuffer.
|
||||
///
|
||||
/// \param Ptr The start of the data to be written. For buffered streams this
|
||||
/// is guaranteed to be the start of the buffer.
|
||||
///
|
||||
/// \param Size The number of bytes to be written.
|
||||
///
|
||||
/// \invariant { Size > 0 }
|
||||
virtual void write_impl(const char *Ptr, size_t Size) = 0;
|
||||
|
||||
// An out of line virtual method to provide a home for the class vtable.
|
||||
virtual void handle();
|
||||
|
||||
/// Return the current position within the stream, not counting the bytes
|
||||
/// currently in the buffer.
|
||||
virtual uint64_t current_pos() const = 0;
|
||||
|
||||
protected:
|
||||
/// Use the provided buffer as the raw_ostream buffer. This is intended for
|
||||
/// use only by subclasses which can arrange for the output to go directly
|
||||
/// into the desired output buffer, instead of being copied on each flush.
|
||||
void SetBuffer(char *BufferStart, size_t Size) {
|
||||
SetBufferAndMode(BufferStart, Size, ExternalBuffer);
|
||||
}
|
||||
|
||||
/// Return an efficient buffer size for the underlying output mechanism.
|
||||
virtual size_t preferred_buffer_size() const;
|
||||
|
||||
/// Return the beginning of the current stream buffer, or 0 if the stream is
|
||||
/// unbuffered.
|
||||
const char *getBufferStart() const { return OutBufStart; }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Private Interface
|
||||
//===--------------------------------------------------------------------===//
|
||||
private:
|
||||
/// Install the given buffer and mode.
|
||||
void SetBufferAndMode(char *BufferStart, size_t Size, BufferKind Mode);
|
||||
|
||||
/// Flush the current buffer, which is known to be non-empty. This outputs the
|
||||
/// currently buffered data and resets the buffer to empty.
|
||||
void flush_nonempty();
|
||||
|
||||
/// Copy data into the buffer. Size must not be greater than the number of
|
||||
/// unused bytes in the buffer.
|
||||
void copy_to_buffer(const char *Ptr, size_t Size);
|
||||
};
|
||||
|
||||
/// An abstract base class for streams implementations that also support a
|
||||
/// pwrite operation. This is useful for code that can mostly stream out data,
|
||||
/// but needs to patch in a header that needs to know the output size.
|
||||
class raw_pwrite_stream : public raw_ostream {
|
||||
virtual void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) = 0;
|
||||
|
||||
public:
|
||||
explicit raw_pwrite_stream(bool Unbuffered = false)
|
||||
: raw_ostream(Unbuffered) {}
|
||||
void pwrite(const char *Ptr, size_t Size, uint64_t Offset) {
|
||||
#ifndef NDBEBUG
|
||||
uint64_t Pos = tell();
|
||||
// /dev/null always reports a pos of 0, so we cannot perform this check
|
||||
// in that case.
|
||||
if (Pos)
|
||||
assert(Size + Offset <= Pos && "We don't support extending the stream");
|
||||
#endif
|
||||
pwrite_impl(Ptr, Size, Offset);
|
||||
}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// File Output Streams
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// A raw_ostream that writes to a file descriptor.
|
||||
///
|
||||
class raw_fd_ostream : public raw_pwrite_stream {
|
||||
int FD;
|
||||
bool ShouldClose;
|
||||
|
||||
/// Error This flag is true if an error of any kind has been detected.
|
||||
///
|
||||
bool Error;
|
||||
|
||||
uint64_t pos;
|
||||
|
||||
bool SupportsSeeking;
|
||||
|
||||
/// See raw_ostream::write_impl.
|
||||
void write_impl(const char *Ptr, size_t Size) override;
|
||||
|
||||
void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) override;
|
||||
|
||||
/// Return the current position within the stream, not counting the bytes
|
||||
/// currently in the buffer.
|
||||
uint64_t current_pos() const override { return pos; }
|
||||
|
||||
/// Determine an efficient buffer size.
|
||||
size_t preferred_buffer_size() const override;
|
||||
|
||||
/// Set the flag indicating that an output error has been encountered.
|
||||
void error_detected() { Error = true; }
|
||||
|
||||
public:
|
||||
/// Open the specified file for writing. If an error occurs, information
|
||||
/// about the error is put into EC, and the stream should be immediately
|
||||
/// destroyed;
|
||||
/// \p Flags allows optional flags to control how the file will be opened.
|
||||
///
|
||||
/// As a special case, if Filename is "-", then the stream will use
|
||||
/// STDOUT_FILENO instead of opening a file. Note that it will still consider
|
||||
/// itself to own the file descriptor. In particular, it will close the
|
||||
/// file descriptor when it is done (this is necessary to detect
|
||||
/// output errors).
|
||||
raw_fd_ostream(StringRef Filename, std::error_code &EC,
|
||||
sys::fs::OpenFlags Flags);
|
||||
|
||||
/// FD is the file descriptor that this writes to. If ShouldClose is true,
|
||||
/// this closes the file when the stream is destroyed.
|
||||
raw_fd_ostream(int fd, bool shouldClose, bool unbuffered=false);
|
||||
|
||||
~raw_fd_ostream() override;
|
||||
|
||||
/// Manually flush the stream and close the file. Note that this does not call
|
||||
/// fsync.
|
||||
void close();
|
||||
|
||||
bool supportsSeeking() { return SupportsSeeking; }
|
||||
|
||||
/// Flushes the stream and repositions the underlying file descriptor position
|
||||
/// to the offset specified from the beginning of the file.
|
||||
uint64_t seek(uint64_t off);
|
||||
|
||||
/// Return the value of the flag in this raw_fd_ostream indicating whether an
|
||||
/// output error has been encountered.
|
||||
/// This doesn't implicitly flush any pending output. Also, it doesn't
|
||||
/// guarantee to detect all errors unless the stream has been closed.
|
||||
bool has_error() const {
|
||||
return Error;
|
||||
}
|
||||
|
||||
/// Set the flag read by has_error() to false. If the error flag is set at the
|
||||
/// time when this raw_ostream's destructor is called, report_fatal_error is
|
||||
/// called to report the error. Use clear_error() after handling the error to
|
||||
/// avoid this behavior.
|
||||
///
|
||||
/// "Errors should never pass silently.
|
||||
/// Unless explicitly silenced."
|
||||
/// - from The Zen of Python, by Tim Peters
|
||||
///
|
||||
void clear_error() {
|
||||
Error = false;
|
||||
}
|
||||
};
|
||||
|
||||
/// This returns a reference to a raw_ostream for standard output. Use it like:
|
||||
/// outs() << "foo" << "bar";
|
||||
raw_ostream &outs();
|
||||
|
||||
/// This returns a reference to a raw_ostream for standard error. Use it like:
|
||||
/// errs() << "foo" << "bar";
|
||||
raw_ostream &errs();
|
||||
|
||||
/// This returns a reference to a raw_ostream which simply discards output.
|
||||
raw_ostream &nulls();
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Output Stream Adaptors
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// A raw_ostream that writes to an std::string. This is a simple adaptor
|
||||
/// class. This class does not encounter output errors.
|
||||
class raw_string_ostream : public raw_ostream {
|
||||
std::string &OS;
|
||||
|
||||
/// See raw_ostream::write_impl.
|
||||
void write_impl(const char *Ptr, size_t Size) override;
|
||||
|
||||
/// Return the current position within the stream, not counting the bytes
|
||||
/// currently in the buffer.
|
||||
uint64_t current_pos() const override { return OS.size(); }
|
||||
|
||||
public:
|
||||
explicit raw_string_ostream(std::string &O) : OS(O) {}
|
||||
~raw_string_ostream() override;
|
||||
|
||||
/// Flushes the stream contents to the target string and returns the string's
|
||||
/// reference.
|
||||
std::string& str() {
|
||||
flush();
|
||||
return OS;
|
||||
}
|
||||
};
|
||||
|
||||
/// A raw_ostream that writes to an SmallVector or SmallString. This is a
|
||||
/// simple adaptor class. This class does not encounter output errors.
|
||||
/// raw_svector_ostream operates without a buffer, delegating all memory
|
||||
/// management to the SmallString. Thus the SmallString is always up-to-date,
|
||||
/// may be used directly and there is no need to call flush().
|
||||
class raw_svector_ostream : public raw_pwrite_stream {
|
||||
SmallVectorImpl<char> &OS;
|
||||
|
||||
/// See raw_ostream::write_impl.
|
||||
void write_impl(const char *Ptr, size_t Size) override;
|
||||
|
||||
void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) override;
|
||||
|
||||
/// Return the current position within the stream.
|
||||
uint64_t current_pos() const override;
|
||||
|
||||
public:
|
||||
/// Construct a new raw_svector_ostream.
|
||||
///
|
||||
/// \param O The vector to write to; this should generally have at least 128
|
||||
/// bytes free to avoid any extraneous memory overhead.
|
||||
explicit raw_svector_ostream(SmallVectorImpl<char> &O) : OS(O) {
|
||||
SetUnbuffered();
|
||||
}
|
||||
~raw_svector_ostream() override {}
|
||||
|
||||
void flush() = delete;
|
||||
|
||||
/// Return a StringRef for the vector contents.
|
||||
StringRef str() { return StringRef(OS.data(), OS.size()); }
|
||||
};
|
||||
|
||||
/// A raw_ostream that discards all output.
|
||||
class raw_null_ostream : public raw_pwrite_stream {
|
||||
/// See raw_ostream::write_impl.
|
||||
void write_impl(const char *Ptr, size_t size) override;
|
||||
void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) override;
|
||||
|
||||
/// Return the current position within the stream, not counting the bytes
|
||||
/// currently in the buffer.
|
||||
uint64_t current_pos() const override;
|
||||
|
||||
public:
|
||||
explicit raw_null_ostream() {}
|
||||
~raw_null_ostream() override;
|
||||
};
|
||||
|
||||
class buffer_ostream : public raw_svector_ostream {
|
||||
raw_ostream &OS;
|
||||
SmallVector<char, 0> Buffer;
|
||||
|
||||
public:
|
||||
buffer_ostream(raw_ostream &OS) : raw_svector_ostream(Buffer), OS(OS) {}
|
||||
~buffer_ostream() override { OS << str(); }
|
||||
};
|
||||
|
||||
} // end llvm namespace
|
||||
|
||||
#endif // LLVM_SUPPORT_RAW_OSTREAM_H
|
||||
95
src/main/native/include/llvm/type_traits.h
Normal file
95
src/main/native/include/llvm/type_traits.h
Normal file
@@ -0,0 +1,95 @@
|
||||
//===- llvm/Support/type_traits.h - Simplfied type traits -------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file provides useful additions to the standard type_traits library.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_TYPE_TRAITS_H
|
||||
#define LLVM_SUPPORT_TYPE_TRAITS_H
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "llvm/Compiler.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// isPodLike - This is a type trait that is used to determine whether a given
|
||||
/// type can be copied around with memcpy instead of running ctors etc.
|
||||
template <typename T>
|
||||
struct isPodLike {
|
||||
// std::is_trivially_copyable is available in libc++ with clang, libstdc++
|
||||
// that comes with GCC 5.
|
||||
#if (__has_feature(is_trivially_copyable) && defined(_LIBCPP_VERSION)) || \
|
||||
(defined(__GNUC__) && __GNUC__ >= 5)
|
||||
// If the compiler supports the is_trivially_copyable trait use it, as it
|
||||
// matches the definition of isPodLike closely.
|
||||
static const bool value = std::is_trivially_copyable<T>::value;
|
||||
#elif __has_feature(is_trivially_copyable)
|
||||
// Use the internal name if the compiler supports is_trivially_copyable but we
|
||||
// don't know if the standard library does. This is the case for clang in
|
||||
// conjunction with libstdc++ from GCC 4.x.
|
||||
static const bool value = __is_trivially_copyable(T);
|
||||
#else
|
||||
// If we don't know anything else, we can (at least) assume that all non-class
|
||||
// types are PODs.
|
||||
static const bool value = !std::is_class<T>::value;
|
||||
#endif
|
||||
};
|
||||
|
||||
// std::pair's are pod-like if their elements are.
|
||||
template<typename T, typename U>
|
||||
struct isPodLike<std::pair<T, U> > {
|
||||
static const bool value = isPodLike<T>::value && isPodLike<U>::value;
|
||||
};
|
||||
|
||||
/// \brief Metafunction that determines whether the given type is either an
|
||||
/// integral type or an enumeration type, including enum classes.
|
||||
///
|
||||
/// Note that this accepts potentially more integral types than is_integral
|
||||
/// because it is based on being implicitly convertible to an integral type.
|
||||
/// Also note that enum classes aren't implicitly convertible to integral types,
|
||||
/// the value may therefore need to be explicitly converted before being used.
|
||||
template <typename T> class is_integral_or_enum {
|
||||
typedef typename std::remove_reference<T>::type UnderlyingT;
|
||||
|
||||
public:
|
||||
static const bool value =
|
||||
!std::is_class<UnderlyingT>::value && // Filter conversion operators.
|
||||
!std::is_pointer<UnderlyingT>::value &&
|
||||
!std::is_floating_point<UnderlyingT>::value &&
|
||||
(std::is_enum<UnderlyingT>::value ||
|
||||
std::is_convertible<UnderlyingT, unsigned long long>::value);
|
||||
};
|
||||
|
||||
/// \brief If T is a pointer, just return it. If it is not, return T&.
|
||||
template<typename T, typename Enable = void>
|
||||
struct add_lvalue_reference_if_not_pointer { typedef T &type; };
|
||||
|
||||
template <typename T>
|
||||
struct add_lvalue_reference_if_not_pointer<
|
||||
T, typename std::enable_if<std::is_pointer<T>::value>::type> {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
/// \brief If T is a pointer to X, return a pointer to const X. If it is not,
|
||||
/// return const T.
|
||||
template<typename T, typename Enable = void>
|
||||
struct add_const_past_pointer { typedef const T type; };
|
||||
|
||||
template <typename T>
|
||||
struct add_const_past_pointer<
|
||||
T, typename std::enable_if<std::is_pointer<T>::value>::type> {
|
||||
typedef const typename std::remove_pointer<T>::type *type;
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
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_
|
||||
30
src/main/native/include/tcpsockets/NetworkAcceptor.h
Normal file
30
src/main/native/include/tcpsockets/NetworkAcceptor.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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_TCPSOCKETS_NETWORKACCEPTOR_H_
|
||||
#define WPIUTIL_TCPSOCKETS_NETWORKACCEPTOR_H_
|
||||
|
||||
#include "tcpsockets/NetworkStream.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
class NetworkAcceptor {
|
||||
public:
|
||||
NetworkAcceptor() = default;
|
||||
virtual ~NetworkAcceptor() = default;
|
||||
|
||||
virtual int start() = 0;
|
||||
virtual void shutdown() = 0;
|
||||
virtual std::unique_ptr<NetworkStream> accept() = 0;
|
||||
|
||||
NetworkAcceptor(const NetworkAcceptor&) = delete;
|
||||
NetworkAcceptor& operator=(const NetworkAcceptor&) = delete;
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_TCPSOCKETS_NETWORKACCEPTOR_H_
|
||||
48
src/main/native/include/tcpsockets/NetworkStream.h
Normal file
48
src/main/native/include/tcpsockets/NetworkStream.h
Normal 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_TCPSOCKETS_NETWORKSTREAM_H_
|
||||
#define WPIUTIL_TCPSOCKETS_NETWORKSTREAM_H_
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "llvm/StringRef.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
class NetworkStream {
|
||||
public:
|
||||
NetworkStream() = default;
|
||||
virtual ~NetworkStream() = default;
|
||||
|
||||
enum Error {
|
||||
kConnectionClosed = 0,
|
||||
kConnectionReset = -1,
|
||||
kConnectionTimedOut = -2,
|
||||
kWouldBlock = -3
|
||||
};
|
||||
|
||||
virtual std::size_t send(const char* buffer, std::size_t len, Error* err) = 0;
|
||||
virtual std::size_t receive(char* buffer, std::size_t len, Error* err,
|
||||
int timeout = 0) = 0;
|
||||
virtual void close() = 0;
|
||||
|
||||
virtual llvm::StringRef getPeerIP() const = 0;
|
||||
virtual int getPeerPort() const = 0;
|
||||
virtual void setNoDelay() = 0;
|
||||
|
||||
// returns false on failure
|
||||
virtual bool setBlocking(bool enabled) = 0;
|
||||
virtual int getNativeHandle() const = 0;
|
||||
|
||||
NetworkStream(const NetworkStream&) = delete;
|
||||
NetworkStream& operator=(const NetworkStream&) = delete;
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_TCPSOCKETS_NETWORKSTREAM_H_
|
||||
37
src/main/native/include/tcpsockets/SocketError.h
Normal file
37
src/main/native/include/tcpsockets/SocketError.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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_TCPSOCKETS_SOCKETERROR_H_
|
||||
#define WPIUTIL_TCPSOCKETS_SOCKETERROR_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <WinSock2.h>
|
||||
#else
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
namespace wpi {
|
||||
|
||||
static inline int SocketErrno() {
|
||||
#ifdef _WIN32
|
||||
return WSAGetLastError();
|
||||
#else
|
||||
return errno;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string SocketStrerror(int code);
|
||||
|
||||
static inline std::string SocketStrerror() {
|
||||
return SocketStrerror(SocketErrno());
|
||||
}
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_TCPSOCKETS_SOCKETERROR_H_
|
||||
57
src/main/native/include/tcpsockets/TCPAcceptor.h
Normal file
57
src/main/native/include/tcpsockets/TCPAcceptor.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
TCPAcceptor.h
|
||||
|
||||
TCPAcceptor class interface. TCPAcceptor provides methods to passively
|
||||
establish TCP/IP connections with clients.
|
||||
|
||||
------------------------------------------
|
||||
|
||||
Copyright © 2013 [Vic Hargrave - http://vichargrave.com]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef WPIUTIL_TCPSOCKETS_TCPACCEPTOR_H_
|
||||
#define WPIUTIL_TCPSOCKETS_TCPACCEPTOR_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "tcpsockets/NetworkAcceptor.h"
|
||||
#include "tcpsockets/TCPStream.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
class Logger;
|
||||
|
||||
class TCPAcceptor : public NetworkAcceptor {
|
||||
int m_lsd;
|
||||
int m_port;
|
||||
std::string m_address;
|
||||
bool m_listening;
|
||||
std::atomic_bool m_shutdown;
|
||||
Logger& m_logger;
|
||||
|
||||
public:
|
||||
TCPAcceptor(int port, const char* address, Logger& logger);
|
||||
~TCPAcceptor();
|
||||
|
||||
int start() override;
|
||||
void shutdown() override;
|
||||
std::unique_ptr<NetworkStream> accept() override;
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_TCPSOCKETS_TCPACCEPTOR_H_
|
||||
44
src/main/native/include/tcpsockets/TCPConnector.h
Normal file
44
src/main/native/include/tcpsockets/TCPConnector.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
TCPConnector.h
|
||||
|
||||
TCPConnector class interface. TCPConnector provides methods to actively
|
||||
establish TCP/IP connections with a server.
|
||||
|
||||
------------------------------------------
|
||||
|
||||
Copyright © 2013 [Vic Hargrave - http://vichargrave.com]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License
|
||||
*/
|
||||
|
||||
#ifndef WPIUTIL_TCPSOCKETS_TCPCONNECTOR_H_
|
||||
#define WPIUTIL_TCPSOCKETS_TCPCONNECTOR_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "tcpsockets/NetworkStream.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
class Logger;
|
||||
|
||||
class TCPConnector {
|
||||
public:
|
||||
static std::unique_ptr<NetworkStream> connect(const char* server, int port,
|
||||
Logger& logger,
|
||||
int timeout = 0);
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_TCPSOCKETS_TCPCONNECTOR_H_
|
||||
76
src/main/native/include/tcpsockets/TCPStream.h
Normal file
76
src/main/native/include/tcpsockets/TCPStream.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
TCPStream.h
|
||||
|
||||
TCPStream class interface. TCPStream provides methods to trasnfer
|
||||
data between peers over a TCP/IP connection.
|
||||
|
||||
------------------------------------------
|
||||
|
||||
Copyright © 2013 [Vic Hargrave - http://vichargrave.com]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef WPIUTIL_TCPSOCKETS_TCPSTREAM_H_
|
||||
#define WPIUTIL_TCPSOCKETS_TCPSTREAM_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#include "tcpsockets/NetworkStream.h"
|
||||
|
||||
struct sockaddr_in;
|
||||
|
||||
namespace wpi {
|
||||
|
||||
class TCPStream : public NetworkStream {
|
||||
int m_sd;
|
||||
std::string m_peerIP;
|
||||
int m_peerPort;
|
||||
bool m_blocking;
|
||||
|
||||
public:
|
||||
friend class TCPAcceptor;
|
||||
friend class TCPConnector;
|
||||
|
||||
~TCPStream();
|
||||
|
||||
std::size_t send(const char* buffer, std::size_t len, Error* err) override;
|
||||
std::size_t receive(char* buffer, std::size_t len, Error* err,
|
||||
int timeout = 0) override;
|
||||
void close() override;
|
||||
|
||||
llvm::StringRef getPeerIP() const override;
|
||||
int getPeerPort() const override;
|
||||
void setNoDelay() override;
|
||||
bool setBlocking(bool enabled) override;
|
||||
int getNativeHandle() const override;
|
||||
|
||||
TCPStream(const TCPStream& stream) = delete;
|
||||
TCPStream& operator=(const TCPStream&) = delete;
|
||||
private:
|
||||
bool WaitForReadEvent(int timeout);
|
||||
|
||||
TCPStream(int sd, sockaddr_in* address);
|
||||
TCPStream() = delete;
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user