mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-27 02:01:42 +00:00
Update LLVM to latest upstream. (#1080)
Also change header guards to WPI header guards. Remove StringRef::c_str() customization, replacing the handful of uses with Twine or SmallString. TCPStream: Include errno.h and make Windows includes lowercase for consistency. Upstream LLVM version: eb4186cca7924fb1706357545311a2fa3de40c59
This commit is contained in:
@@ -7,110 +7,24 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the AlignOf function that computes alignments for
|
||||
// arbitrary types.
|
||||
// This file defines the AlignedCharArray and AlignedCharArrayUnion classes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_ALIGNOF_H
|
||||
#define LLVM_SUPPORT_ALIGNOF_H
|
||||
#ifndef WPIUTIL_WPI_ALIGNOF_H
|
||||
#define WPIUTIL_WPI_ALIGNOF_H
|
||||
|
||||
#include "wpi/Compiler.h"
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
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 wpi::AlignOf<X>::<anonymous>' and 'enum
|
||||
// wpi::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(::wpi::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.
|
||||
/// 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
|
||||
/// specialization to cope with MSVC (at least till 2015) 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.
|
||||
@@ -118,41 +32,14 @@ inline unsigned alignOf() { return AlignOf<T>::Alignment; }
|
||||
// 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];
|
||||
LLVM_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.
|
||||
/// Create a type with an aligned char buffer.
|
||||
template<std::size_t Alignment, std::size_t Size>
|
||||
struct AlignedCharArray;
|
||||
|
||||
@@ -237,7 +124,7 @@ union SizerImpl {
|
||||
};
|
||||
} // end namespace detail
|
||||
|
||||
/// \brief This union template exposes a suitably aligned and sized character
|
||||
/// 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
|
||||
@@ -249,8 +136,8 @@ template <typename T1,
|
||||
typename T5 = char, typename T6 = char, typename T7 = char,
|
||||
typename T8 = char, typename T9 = char, typename T10 = char>
|
||||
struct AlignedCharArrayUnion : wpi::AlignedCharArray<
|
||||
AlignOf<wpi::detail::AlignerImpl<T1, T2, T3, T4, T5,
|
||||
T6, T7, T8, T9, T10> >::Alignment,
|
||||
alignof(wpi::detail::AlignerImpl<T1, T2, T3, T4, T5,
|
||||
T6, T7, T8, T9, T10>),
|
||||
sizeof(::wpi::detail::SizerImpl<T1, T2, T3, T4, T5,
|
||||
T6, T7, T8, T9, T10>)> {
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//===--- ArrayRef.h - Array Reference Wrapper -------------------*- C++ -*-===//
|
||||
//===- ArrayRef.h - Array Reference Wrapper ---------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@@ -7,13 +7,22 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_ARRAYREF_H
|
||||
#define LLVM_ADT_ARRAYREF_H
|
||||
#ifndef WPIUTIL_WPI_ARRAYREF_H
|
||||
#define WPIUTIL_WPI_ARRAYREF_H
|
||||
|
||||
#include "wpi/Compiler.h"
|
||||
#include "wpi/Hashing.h"
|
||||
#include "wpi/None.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/STLExtras.h"
|
||||
#include "wpi/Compiler.h"
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace wpi {
|
||||
@@ -29,31 +38,30 @@ namespace wpi {
|
||||
/// This is intended to be trivially copyable, so it should be passed by
|
||||
/// value.
|
||||
template<typename T>
|
||||
class ArrayRef {
|
||||
class LLVM_NODISCARD ArrayRef {
|
||||
public:
|
||||
typedef const T *iterator;
|
||||
typedef const T *const_iterator;
|
||||
typedef size_t size_type;
|
||||
typedef T value_type;
|
||||
|
||||
typedef std::reverse_iterator<iterator> reverse_iterator;
|
||||
using iterator = const T *;
|
||||
using const_iterator = const T *;
|
||||
using size_type = size_t;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using value_type = T;
|
||||
|
||||
private:
|
||||
/// The start of the array, in an external buffer.
|
||||
const T *Data;
|
||||
const T *Data = nullptr;
|
||||
|
||||
/// The number of elements.
|
||||
size_type Length;
|
||||
size_type Length = 0;
|
||||
|
||||
public:
|
||||
/// @name Constructors
|
||||
/// @{
|
||||
|
||||
/// Construct an empty ArrayRef.
|
||||
/*implicit*/ ArrayRef() : Data(nullptr), Length(0) {}
|
||||
/*implicit*/ ArrayRef() = default;
|
||||
|
||||
/// Construct an empty ArrayRef from None.
|
||||
/*implicit*/ ArrayRef(NoneType) : Data(nullptr), Length(0) {}
|
||||
/*implicit*/ ArrayRef(NoneType) {}
|
||||
|
||||
/// Construct an ArrayRef from a single element.
|
||||
/*implicit*/ ArrayRef(const T &OneElt)
|
||||
@@ -80,10 +88,14 @@ namespace wpi {
|
||||
/*implicit*/ ArrayRef(const std::vector<T, A> &Vec)
|
||||
: Data(Vec.data()), Length(Vec.size()) {}
|
||||
|
||||
/// Construct an ArrayRef from a std::array
|
||||
template <size_t N>
|
||||
/*implicit*/ constexpr ArrayRef(const std::array<T, N> &Arr)
|
||||
: Data(Arr.data()), Length(N) {}
|
||||
|
||||
/// Construct an ArrayRef from a C array.
|
||||
template <size_t N>
|
||||
/*implicit*/ LLVM_CONSTEXPR ArrayRef(const T (&Arr)[N])
|
||||
: Data(Arr), Length(N) {}
|
||||
/*implicit*/ 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)
|
||||
@@ -162,12 +174,6 @@ namespace wpi {
|
||||
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 {
|
||||
@@ -175,18 +181,59 @@ namespace wpi {
|
||||
return ArrayRef<T>(data()+N, M);
|
||||
}
|
||||
|
||||
/// \brief Drop the first \p N elements of the array.
|
||||
/// slice(n) - Chop off the first N elements of the array.
|
||||
ArrayRef<T> slice(size_t N) const { return slice(N, size() - N); }
|
||||
|
||||
/// 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.
|
||||
/// 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);
|
||||
}
|
||||
|
||||
/// Return a copy of *this with the first N elements satisfying the
|
||||
/// given predicate removed.
|
||||
template <class PredicateT> ArrayRef<T> drop_while(PredicateT Pred) const {
|
||||
return ArrayRef<T>(find_if_not(*this, Pred), end());
|
||||
}
|
||||
|
||||
/// Return a copy of *this with the first N elements not satisfying
|
||||
/// the given predicate removed.
|
||||
template <class PredicateT> ArrayRef<T> drop_until(PredicateT Pred) const {
|
||||
return ArrayRef<T>(find_if(*this, Pred), end());
|
||||
}
|
||||
|
||||
/// Return a copy of *this with only the first \p N elements.
|
||||
ArrayRef<T> take_front(size_t N = 1) const {
|
||||
if (N >= size())
|
||||
return *this;
|
||||
return drop_back(size() - N);
|
||||
}
|
||||
|
||||
/// Return a copy of *this with only the last \p N elements.
|
||||
ArrayRef<T> take_back(size_t N = 1) const {
|
||||
if (N >= size())
|
||||
return *this;
|
||||
return drop_front(size() - N);
|
||||
}
|
||||
|
||||
/// Return the first N elements of this Array that satisfy the given
|
||||
/// predicate.
|
||||
template <class PredicateT> ArrayRef<T> take_while(PredicateT Pred) const {
|
||||
return ArrayRef<T>(begin(), find_if_not(*this, Pred));
|
||||
}
|
||||
|
||||
/// Return the first N elements of this Array that don't satisfy the
|
||||
/// given predicate.
|
||||
template <class PredicateT> ArrayRef<T> take_until(PredicateT Pred) const {
|
||||
return ArrayRef<T>(begin(), find_if(*this, Pred));
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Operator Overloads
|
||||
/// @{
|
||||
@@ -195,6 +242,22 @@ namespace wpi {
|
||||
return Data[Index];
|
||||
}
|
||||
|
||||
/// Disallow accidental assignment from a temporary.
|
||||
///
|
||||
/// The declaration here is extra complicated so that "arrayRef = {}"
|
||||
/// continues to select the move assignment operator.
|
||||
template <typename U>
|
||||
typename std::enable_if<std::is_same<U, T>::value, ArrayRef<T>>::type &
|
||||
operator=(U &&Temporary) = delete;
|
||||
|
||||
/// Disallow accidental assignment from a temporary.
|
||||
///
|
||||
/// The declaration here is extra complicated so that "arrayRef = {}"
|
||||
/// continues to select the move assignment operator.
|
||||
template <typename U>
|
||||
typename std::enable_if<std::is_same<U, T>::value, ArrayRef<T>>::type &
|
||||
operator=(std::initializer_list<U>) = delete;
|
||||
|
||||
/// @}
|
||||
/// @name Expensive Operations
|
||||
/// @{
|
||||
@@ -225,14 +288,13 @@ namespace wpi {
|
||||
/// This is intended to be trivially copyable, so it should be passed by
|
||||
/// value.
|
||||
template<typename T>
|
||||
class MutableArrayRef : public ArrayRef<T> {
|
||||
class LLVM_NODISCARD MutableArrayRef : public ArrayRef<T> {
|
||||
public:
|
||||
typedef T *iterator;
|
||||
|
||||
typedef std::reverse_iterator<iterator> reverse_iterator;
|
||||
using iterator = T *;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
|
||||
/// Construct an empty MutableArrayRef.
|
||||
/*implicit*/ MutableArrayRef() : ArrayRef<T>() {}
|
||||
/*implicit*/ MutableArrayRef() = default;
|
||||
|
||||
/// Construct an empty MutableArrayRef from None.
|
||||
/*implicit*/ MutableArrayRef(NoneType) : ArrayRef<T>() {}
|
||||
@@ -255,10 +317,14 @@ namespace wpi {
|
||||
/*implicit*/ MutableArrayRef(std::vector<T> &Vec)
|
||||
: ArrayRef<T>(Vec) {}
|
||||
|
||||
/// Construct an ArrayRef from a std::array
|
||||
template <size_t N>
|
||||
/*implicit*/ constexpr MutableArrayRef(std::array<T, N> &Arr)
|
||||
: ArrayRef<T>(Arr) {}
|
||||
|
||||
/// Construct an MutableArrayRef from a C array.
|
||||
template <size_t N>
|
||||
/*implicit*/ LLVM_CONSTEXPR MutableArrayRef(T (&Arr)[N])
|
||||
: ArrayRef<T>(Arr) {}
|
||||
/*implicit*/ constexpr MutableArrayRef(T (&Arr)[N]) : ArrayRef<T>(Arr) {}
|
||||
|
||||
T *data() const { return const_cast<T*>(ArrayRef<T>::data()); }
|
||||
|
||||
@@ -280,20 +346,19 @@ namespace wpi {
|
||||
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);
|
||||
assert(N + M <= this->size() && "Invalid specifier");
|
||||
return MutableArrayRef<T>(this->data() + N, M);
|
||||
}
|
||||
|
||||
/// \brief Drop the first \p N elements of the array.
|
||||
/// slice(n) - Chop off the first N elements of the array.
|
||||
MutableArrayRef<T> slice(size_t N) const {
|
||||
return slice(N, this->size() - N);
|
||||
}
|
||||
|
||||
/// 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);
|
||||
@@ -304,6 +369,48 @@ namespace wpi {
|
||||
return slice(0, this->size() - N);
|
||||
}
|
||||
|
||||
/// Return a copy of *this with the first N elements satisfying the
|
||||
/// given predicate removed.
|
||||
template <class PredicateT>
|
||||
MutableArrayRef<T> drop_while(PredicateT Pred) const {
|
||||
return MutableArrayRef<T>(find_if_not(*this, Pred), end());
|
||||
}
|
||||
|
||||
/// Return a copy of *this with the first N elements not satisfying
|
||||
/// the given predicate removed.
|
||||
template <class PredicateT>
|
||||
MutableArrayRef<T> drop_until(PredicateT Pred) const {
|
||||
return MutableArrayRef<T>(find_if(*this, Pred), end());
|
||||
}
|
||||
|
||||
/// Return a copy of *this with only the first \p N elements.
|
||||
MutableArrayRef<T> take_front(size_t N = 1) const {
|
||||
if (N >= this->size())
|
||||
return *this;
|
||||
return drop_back(this->size() - N);
|
||||
}
|
||||
|
||||
/// Return a copy of *this with only the last \p N elements.
|
||||
MutableArrayRef<T> take_back(size_t N = 1) const {
|
||||
if (N >= this->size())
|
||||
return *this;
|
||||
return drop_front(this->size() - N);
|
||||
}
|
||||
|
||||
/// Return the first N elements of this Array that satisfy the given
|
||||
/// predicate.
|
||||
template <class PredicateT>
|
||||
MutableArrayRef<T> take_while(PredicateT Pred) const {
|
||||
return MutableArrayRef<T>(begin(), find_if_not(*this, Pred));
|
||||
}
|
||||
|
||||
/// Return the first N elements of this Array that don't satisfy the
|
||||
/// given predicate.
|
||||
template <class PredicateT>
|
||||
MutableArrayRef<T> take_until(PredicateT Pred) const {
|
||||
return MutableArrayRef<T>(begin(), find_if(*this, Pred));
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Operator Overloads
|
||||
/// @{
|
||||
@@ -313,6 +420,29 @@ namespace wpi {
|
||||
}
|
||||
};
|
||||
|
||||
/// This is a MutableArrayRef that owns its array.
|
||||
template <typename T> class OwningArrayRef : public MutableArrayRef<T> {
|
||||
public:
|
||||
OwningArrayRef() = default;
|
||||
OwningArrayRef(size_t Size) : MutableArrayRef<T>(new T[Size], Size) {}
|
||||
|
||||
OwningArrayRef(ArrayRef<T> Data)
|
||||
: MutableArrayRef<T>(new T[Data.size()], Data.size()) {
|
||||
std::copy(Data.begin(), Data.end(), this->begin());
|
||||
}
|
||||
|
||||
OwningArrayRef(OwningArrayRef &&Other) { *this = Other; }
|
||||
|
||||
OwningArrayRef &operator=(OwningArrayRef &&Other) {
|
||||
delete[] this->data();
|
||||
this->MutableArrayRef<T>::operator=(Other);
|
||||
Other.MutableArrayRef<T>::operator=(MutableArrayRef<T>());
|
||||
return *this;
|
||||
}
|
||||
|
||||
~OwningArrayRef() { delete[] this->data(); }
|
||||
};
|
||||
|
||||
/// @name ArrayRef Convenience constructors
|
||||
/// @{
|
||||
|
||||
@@ -368,6 +498,18 @@ namespace wpi {
|
||||
return ArrayRef<T>(Arr);
|
||||
}
|
||||
|
||||
/// Construct a MutableArrayRef from a single element.
|
||||
template<typename T>
|
||||
MutableArrayRef<T> makeMutableArrayRef(T &OneElt) {
|
||||
return OneElt;
|
||||
}
|
||||
|
||||
/// Construct a MutableArrayRef from a pointer and length.
|
||||
template<typename T>
|
||||
MutableArrayRef<T> makeMutableArrayRef(T *data, size_t length) {
|
||||
return MutableArrayRef<T>(data, length);
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name ArrayRef Comparison Operators
|
||||
/// @{
|
||||
@@ -386,13 +528,14 @@ namespace wpi {
|
||||
|
||||
// ArrayRefs can be treated like a POD type.
|
||||
template <typename T> struct isPodLike;
|
||||
template <typename T> struct isPodLike<ArrayRef<T> > {
|
||||
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 wpi
|
||||
|
||||
#endif // LLVM_ADT_ARRAYREF_H
|
||||
|
||||
@@ -12,8 +12,12 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_COMPILER_H
|
||||
#define LLVM_SUPPORT_COMPILER_H
|
||||
#ifndef WPIUTIL_WPI_COMPILER_H
|
||||
#define WPIUTIL_WPI_COMPILER_H
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <sal.h>
|
||||
#endif
|
||||
|
||||
#ifndef __has_feature
|
||||
# define __has_feature(x) 0
|
||||
@@ -27,12 +31,16 @@
|
||||
# define __has_attribute(x) 0
|
||||
#endif
|
||||
|
||||
#ifndef __has_cpp_attribute
|
||||
# define __has_cpp_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
|
||||
/// 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__)
|
||||
@@ -47,39 +55,116 @@
|
||||
# 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
|
||||
/// \macro LLVM_MSC_PREREQ
|
||||
/// Is the compiler MSVC of at least the specified version?
|
||||
/// The common \param version values to check for are:
|
||||
/// * 1900: Microsoft Visual Studio 2015 / 14.0
|
||||
#ifndef LLVM_MSC_PREREQ
|
||||
#ifdef _MSC_VER
|
||||
#define LLVM_MSC_PREREQ(version) (_MSC_VER >= (version))
|
||||
|
||||
// We require at least MSVC 2015.
|
||||
#if !LLVM_MSC_PREREQ(1900)
|
||||
#error wpiutil requires at least MSVC 2015.
|
||||
#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
|
||||
#define LLVM_MSC_PREREQ(version) 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef LLVM_UNLIKELY
|
||||
/// Does the compiler support ref-qualifiers for *this?
|
||||
///
|
||||
/// Sadly, this is separate from just rvalue reference support because GCC
|
||||
/// and MSVC implemented this later than everything else.
|
||||
#ifndef LLVM_HAS_RVALUE_REFERENCE_THIS
|
||||
#if __has_feature(cxx_rvalue_references) || LLVM_GNUC_PREREQ(4, 8, 1)
|
||||
#define LLVM_HAS_RVALUE_REFERENCE_THIS 1
|
||||
#else
|
||||
#define LLVM_HAS_RVALUE_REFERENCE_THIS 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// Expands to '&' if ref-qualifiers for *this are supported.
|
||||
///
|
||||
/// This can be used to provide lvalue/rvalue overrides of member functions.
|
||||
/// The rvalue override should be guarded by LLVM_HAS_RVALUE_REFERENCE_THIS
|
||||
#ifndef LLVM_LVALUE_FUNCTION
|
||||
#if LLVM_HAS_RVALUE_REFERENCE_THIS
|
||||
#define LLVM_LVALUE_FUNCTION &
|
||||
#else
|
||||
#define LLVM_LVALUE_FUNCTION
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef LLVM_PREFETCH
|
||||
#if defined(__GNUC__)
|
||||
#define LLVM_PREFETCH(addr, rw, locality) __builtin_prefetch(addr, rw, locality)
|
||||
#else
|
||||
#define LLVM_PREFETCH(addr, rw, locality)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef LLVM_ATTRIBUTE_USED
|
||||
#if __has_attribute(used) || LLVM_GNUC_PREREQ(3, 1, 0)
|
||||
#define LLVM_ATTRIBUTE_USED __attribute__((__used__))
|
||||
#else
|
||||
#define LLVM_ATTRIBUTE_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// LLVM_NODISCARD - Warn if a type or return value is discarded.
|
||||
#ifndef LLVM_NODISCARD
|
||||
#if __cplusplus > 201402L && __has_cpp_attribute(nodiscard)
|
||||
#define LLVM_NODISCARD [[nodiscard]]
|
||||
#elif !__cplusplus
|
||||
// Workaround for llvm.org/PR23435, since clang 3.6 and below emit a spurious
|
||||
// error when __has_cpp_attribute is given a scoped attribute in C mode.
|
||||
#define LLVM_NODISCARD
|
||||
#elif __has_cpp_attribute(clang::warn_unused_result)
|
||||
#define LLVM_NODISCARD [[clang::warn_unused_result]]
|
||||
#else
|
||||
#define LLVM_NODISCARD
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Some compilers warn about unused functions. When a function is sometimes
|
||||
// used or not depending on build settings (e.g. a function only called from
|
||||
// within "assert"), this attribute can be used to suppress such warnings.
|
||||
//
|
||||
// However, it shouldn't be used for unused *variables*, as those have a much
|
||||
// more portable solution:
|
||||
// (void)unused_var_name;
|
||||
// Prefer cast-to-void wherever it is sufficient.
|
||||
#ifndef LLVM_ATTRIBUTE_UNUSED
|
||||
#if __has_attribute(unused) || LLVM_GNUC_PREREQ(3, 1, 0)
|
||||
#define LLVM_ATTRIBUTE_UNUSED __attribute__((__unused__))
|
||||
#else
|
||||
#define LLVM_ATTRIBUTE_UNUSED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef LLVM_READNONE
|
||||
// Prior to clang 3.2, clang did not accept any spelling of
|
||||
// __has_attribute(const), so assume it is supported.
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
// aka 'CONST' but following LLVM Conventions.
|
||||
#define LLVM_READNONE __attribute__((__const__))
|
||||
#else
|
||||
#define LLVM_READNONE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef LLVM_READONLY
|
||||
#if __has_attribute(pure) || defined(__GNUC__)
|
||||
// aka 'PURE' but following LLVM Conventions.
|
||||
#define LLVM_READONLY __attribute__((__pure__))
|
||||
#else
|
||||
#define LLVM_READONLY
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef LLVM_LIKELY
|
||||
#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)
|
||||
@@ -89,4 +174,253 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// LLVM_ATTRIBUTE_NOINLINE - On compilers where we have a directive to do so,
|
||||
/// mark a method "not for inlining".
|
||||
#ifndef LLVM_ATTRIBUTE_NOINLINE
|
||||
#if __has_attribute(noinline) || LLVM_GNUC_PREREQ(3, 4, 0)
|
||||
#define LLVM_ATTRIBUTE_NOINLINE __attribute__((noinline))
|
||||
#elif defined(_MSC_VER)
|
||||
#define LLVM_ATTRIBUTE_NOINLINE __declspec(noinline)
|
||||
#else
|
||||
#define LLVM_ATTRIBUTE_NOINLINE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// LLVM_ATTRIBUTE_ALWAYS_INLINE - On compilers where we have a directive to do
|
||||
/// so, mark a method "always inline" because it is performance sensitive. GCC
|
||||
/// 3.4 supported this but is buggy in various cases and produces unimplemented
|
||||
/// errors, just use it in GCC 4.0 and later.
|
||||
#ifndef LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
#if __has_attribute(always_inline) || LLVM_GNUC_PREREQ(4, 0, 0)
|
||||
#define LLVM_ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline)) inline
|
||||
#elif defined(_MSC_VER)
|
||||
#define LLVM_ATTRIBUTE_ALWAYS_INLINE __forceinline
|
||||
#else
|
||||
#define LLVM_ATTRIBUTE_ALWAYS_INLINE inline
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef LLVM_ATTRIBUTE_NORETURN
|
||||
#ifdef __GNUC__
|
||||
#define LLVM_ATTRIBUTE_NORETURN __attribute__((noreturn))
|
||||
#elif defined(_MSC_VER)
|
||||
#define LLVM_ATTRIBUTE_NORETURN __declspec(noreturn)
|
||||
#else
|
||||
#define LLVM_ATTRIBUTE_NORETURN
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef LLVM_ATTRIBUTE_RETURNS_NONNULL
|
||||
#if __has_attribute(returns_nonnull) || LLVM_GNUC_PREREQ(4, 9, 0)
|
||||
#define LLVM_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull))
|
||||
#elif defined(_MSC_VER)
|
||||
#define LLVM_ATTRIBUTE_RETURNS_NONNULL _Ret_notnull_
|
||||
#else
|
||||
#define LLVM_ATTRIBUTE_RETURNS_NONNULL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_ATTRIBUTE_RETURNS_NOALIAS Used to mark a function as returning a
|
||||
/// pointer that does not alias any other valid pointer.
|
||||
#ifndef LLVM_ATTRIBUTE_RETURNS_NOALIAS
|
||||
#ifdef __GNUC__
|
||||
#define LLVM_ATTRIBUTE_RETURNS_NOALIAS __attribute__((__malloc__))
|
||||
#elif defined(_MSC_VER)
|
||||
#define LLVM_ATTRIBUTE_RETURNS_NOALIAS __declspec(restrict)
|
||||
#else
|
||||
#define LLVM_ATTRIBUTE_RETURNS_NOALIAS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// LLVM_FALLTHROUGH - Mark fallthrough cases in switch statements.
|
||||
#ifndef LLVM_FALLTHROUGH
|
||||
#if __cplusplus > 201402L && __has_cpp_attribute(fallthrough)
|
||||
#define LLVM_FALLTHROUGH [[fallthrough]]
|
||||
#elif __has_cpp_attribute(gnu::fallthrough)
|
||||
#define LLVM_FALLTHROUGH [[gnu::fallthrough]]
|
||||
#elif !__cplusplus
|
||||
// Workaround for llvm.org/PR23435, since clang 3.6 and below emit a spurious
|
||||
// error when __has_cpp_attribute is given a scoped attribute in C mode.
|
||||
#define LLVM_FALLTHROUGH
|
||||
#elif __has_cpp_attribute(clang::fallthrough)
|
||||
#define LLVM_FALLTHROUGH [[clang::fallthrough]]
|
||||
#else
|
||||
#define LLVM_FALLTHROUGH
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// LLVM_EXTENSION - Support compilers where we have a keyword to suppress
|
||||
/// pedantic diagnostics.
|
||||
#ifndef LLVM_EXTENSION
|
||||
#ifdef __GNUC__
|
||||
#define LLVM_EXTENSION __extension__
|
||||
#else
|
||||
#define LLVM_EXTENSION
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// LLVM_ATTRIBUTE_DEPRECATED(decl, "message")
|
||||
#ifndef LLVM_ATTRIBUTE_DEPRECATED
|
||||
#if __has_feature(attribute_deprecated_with_message)
|
||||
# define LLVM_ATTRIBUTE_DEPRECATED(decl, message) \
|
||||
decl __attribute__((deprecated(message)))
|
||||
#elif defined(__GNUC__)
|
||||
# define LLVM_ATTRIBUTE_DEPRECATED(decl, message) \
|
||||
decl __attribute__((deprecated))
|
||||
#elif defined(_MSC_VER)
|
||||
# define LLVM_ATTRIBUTE_DEPRECATED(decl, message) \
|
||||
__declspec(deprecated(message)) decl
|
||||
#else
|
||||
# define LLVM_ATTRIBUTE_DEPRECATED(decl, message) \
|
||||
decl
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// LLVM_BUILTIN_UNREACHABLE - On compilers which support it, expands
|
||||
/// to an expression which states that it is undefined behavior for the
|
||||
/// compiler to reach this point. Otherwise is not defined.
|
||||
#ifndef LLVM_BUILTIN_UNREACHABLE
|
||||
#if __has_builtin(__builtin_unreachable) || LLVM_GNUC_PREREQ(4, 5, 0)
|
||||
# define LLVM_BUILTIN_UNREACHABLE __builtin_unreachable()
|
||||
#elif defined(_MSC_VER)
|
||||
# define LLVM_BUILTIN_UNREACHABLE __assume(false)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_ASSUME_ALIGNED
|
||||
/// Returns a pointer with an assumed alignment.
|
||||
#ifndef LLVM_ASSUME_ALIGNED
|
||||
#if __has_builtin(__builtin_assume_aligned) || LLVM_GNUC_PREREQ(4, 7, 0)
|
||||
# define LLVM_ASSUME_ALIGNED(p, a) __builtin_assume_aligned(p, a)
|
||||
#elif defined(LLVM_BUILTIN_UNREACHABLE)
|
||||
// As of today, clang does not support __builtin_assume_aligned.
|
||||
# define LLVM_ASSUME_ALIGNED(p, a) \
|
||||
(((uintptr_t(p) % (a)) == 0) ? (p) : (LLVM_BUILTIN_UNREACHABLE, (p)))
|
||||
#else
|
||||
# define LLVM_ASSUME_ALIGNED(p, a) (p)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_ALIGNAS
|
||||
/// Used to specify a minimum alignment for a structure or variable.
|
||||
#ifndef LLVM_ALIGNAS
|
||||
#if __GNUC__ && !__has_feature(cxx_alignas) && !LLVM_GNUC_PREREQ(4, 8, 1)
|
||||
# define LLVM_ALIGNAS(x) __attribute__((aligned(x)))
|
||||
#else
|
||||
# define LLVM_ALIGNAS(x) alignas(x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_PACKED
|
||||
/// Used to specify a packed structure.
|
||||
/// LLVM_PACKED(
|
||||
/// struct A {
|
||||
/// int i;
|
||||
/// int j;
|
||||
/// int k;
|
||||
/// long long l;
|
||||
/// });
|
||||
///
|
||||
/// LLVM_PACKED_START
|
||||
/// struct B {
|
||||
/// int i;
|
||||
/// int j;
|
||||
/// int k;
|
||||
/// long long l;
|
||||
/// };
|
||||
/// LLVM_PACKED_END
|
||||
#ifndef LLVM_PACKED
|
||||
#ifdef _MSC_VER
|
||||
# define LLVM_PACKED(d) __pragma(pack(push, 1)) d __pragma(pack(pop))
|
||||
# define LLVM_PACKED_START __pragma(pack(push, 1))
|
||||
# define LLVM_PACKED_END __pragma(pack(pop))
|
||||
#else
|
||||
# define LLVM_PACKED(d) d __attribute__((packed))
|
||||
# define LLVM_PACKED_START _Pragma("pack(push, 1)")
|
||||
# define LLVM_PACKED_END _Pragma("pack(pop)")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_PTR_SIZE
|
||||
/// A constant integer equivalent to the value of sizeof(void*).
|
||||
/// Generally used in combination with LLVM_ALIGNAS or when doing computation in
|
||||
/// the preprocessor.
|
||||
#ifndef LLVM_PTR_SIZE
|
||||
#ifdef __SIZEOF_POINTER__
|
||||
# define LLVM_PTR_SIZE __SIZEOF_POINTER__
|
||||
#elif defined(_WIN64)
|
||||
# define LLVM_PTR_SIZE 8
|
||||
#elif defined(_WIN32)
|
||||
# define LLVM_PTR_SIZE 4
|
||||
#elif defined(_MSC_VER)
|
||||
# error "could not determine LLVM_PTR_SIZE as a constant int for MSVC"
|
||||
#else
|
||||
# define LLVM_PTR_SIZE sizeof(void *)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_NO_SANITIZE
|
||||
/// Disable a particular sanitizer for a function.
|
||||
#ifndef LLVM_NO_SANITIZE
|
||||
#if __has_attribute(no_sanitize)
|
||||
#define LLVM_NO_SANITIZE(KIND) __attribute__((no_sanitize(KIND)))
|
||||
#else
|
||||
#define LLVM_NO_SANITIZE(KIND)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// Mark debug helper function definitions like dump() that should not be
|
||||
/// stripped from debug builds.
|
||||
/// Note that you should also surround dump() functions with
|
||||
/// `#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)` so they do always
|
||||
/// get stripped in release builds.
|
||||
// FIXME: Move this to a private config.h as it's not usable in public headers.
|
||||
#ifndef LLVM_DUMP_METHOD
|
||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE LLVM_ATTRIBUTE_USED
|
||||
#else
|
||||
#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_PRETTY_FUNCTION
|
||||
/// Gets a user-friendly looking function signature for the current scope
|
||||
/// using the best available method on each platform. The exact format of the
|
||||
/// resulting string is implementation specific and non-portable, so this should
|
||||
/// only be used, for example, for logging or diagnostics.
|
||||
#ifndef LLVM_PRETTY_FUNCTION
|
||||
#if defined(_MSC_VER)
|
||||
#define LLVM_PRETTY_FUNCTION __FUNCSIG__
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
#define LLVM_PRETTY_FUNCTION __PRETTY_FUNCTION__
|
||||
#else
|
||||
#define LLVM_PRETTY_FUNCTION __func__
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_THREAD_LOCAL
|
||||
/// A thread-local storage specifier which can be used with globals,
|
||||
/// extern globals, and static globals.
|
||||
///
|
||||
/// This is essentially an extremely restricted analog to C++11's thread_local
|
||||
/// support, and uses that when available. However, it falls back on
|
||||
/// platform-specific or vendor-provided extensions when necessary. These
|
||||
/// extensions don't support many of the C++11 thread_local's features. You
|
||||
/// should only use this for PODs that you can statically initialize to
|
||||
/// some constant value. In almost all circumstances this is most appropriate
|
||||
/// for use with a pointer, integer, or small aggregation of pointers and
|
||||
/// integers.
|
||||
#ifndef LLVM_THREAD_LOCAL
|
||||
#if __has_feature(cxx_thread_local)
|
||||
#define LLVM_THREAD_LOCAL thread_local
|
||||
#elif defined(_MSC_VER)
|
||||
// MSVC supports this with a __declspec.
|
||||
#define LLVM_THREAD_LOCAL __declspec(thread)
|
||||
#else
|
||||
// Clang, GCC, and other compatible compilers used __thread prior to C++11 and
|
||||
// we only need the restricted functionality that provides.
|
||||
#define LLVM_THREAD_LOCAL __thread
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -90,6 +90,17 @@
|
||||
#ifndef LLVM_SUPPORT_CONVERTUTF_H
|
||||
#define LLVM_SUPPORT_CONVERTUTF_H
|
||||
|
||||
#include "wpi/ArrayRef.h"
|
||||
#include "wpi/StringRef.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
// Wrap everything in namespace wpi so that programs can link with wpiutil and
|
||||
// their own version of the unicode libraries.
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
The following 4 definitions are compiler-specific.
|
||||
The C standard does not guarantee that wchar_t has at least
|
||||
@@ -127,11 +138,6 @@ typedef enum {
|
||||
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);
|
||||
@@ -174,16 +180,9 @@ Boolean isLegalUTF8String(const UTF8 **source, const UTF8 *sourceEnd);
|
||||
|
||||
unsigned getNumBytesForUTF8(UTF8 firstByte);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
/* Below are LLVM-specific wrappers of the functions above. */
|
||||
|
||||
#include "wpi/ArrayRef.h"
|
||||
#include "wpi/StringRef.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/**
|
||||
* Convert an Unicode code point to UTF8 sequence.
|
||||
@@ -249,7 +248,3 @@ bool convertUTF8ToUTF16String(StringRef SrcUTF8,
|
||||
} /* end namespace wpi */
|
||||
|
||||
#endif
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
#endif
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_DENSEMAP_H
|
||||
#define LLVM_ADT_DENSEMAP_H
|
||||
#ifndef WPIUTIL_WPI_DENSEMAP_H
|
||||
#define WPIUTIL_WPI_DENSEMAP_H
|
||||
|
||||
#include "wpi/DenseMapInfo.h"
|
||||
#include "wpi/EpochTracker.h"
|
||||
@@ -23,16 +23,17 @@
|
||||
#include "wpi/type_traits.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
namespace detail {
|
||||
|
||||
// We extend a pair to allow users to override the bucket type with their own
|
||||
// implementation without requiring two members.
|
||||
template <typename KeyT, typename ValueT>
|
||||
@@ -42,7 +43,8 @@ struct DenseMapPair : public std::pair<KeyT, ValueT> {
|
||||
ValueT &getSecond() { return std::pair<KeyT, ValueT>::second; }
|
||||
const ValueT &getSecond() const { return std::pair<KeyT, ValueT>::second; }
|
||||
};
|
||||
}
|
||||
|
||||
} // end namespace detail
|
||||
|
||||
template <
|
||||
typename KeyT, typename ValueT, typename KeyInfoT = DenseMapInfo<KeyT>,
|
||||
@@ -52,31 +54,39 @@ class DenseMapIterator;
|
||||
template <typename DerivedT, typename KeyT, typename ValueT, typename KeyInfoT,
|
||||
typename BucketT>
|
||||
class DenseMapBase : public DebugEpochBase {
|
||||
public:
|
||||
typedef unsigned size_type;
|
||||
typedef KeyT key_type;
|
||||
typedef ValueT mapped_type;
|
||||
typedef BucketT value_type;
|
||||
template <typename T>
|
||||
using const_arg_type_t = typename const_pointer_or_const_ref<T>::type;
|
||||
|
||||
public:
|
||||
using size_type = unsigned;
|
||||
using key_type = KeyT;
|
||||
using mapped_type = ValueT;
|
||||
using value_type = BucketT;
|
||||
|
||||
using iterator = DenseMapIterator<KeyT, ValueT, KeyInfoT, BucketT>;
|
||||
using const_iterator =
|
||||
DenseMapIterator<KeyT, ValueT, KeyInfoT, BucketT, true>;
|
||||
|
||||
typedef DenseMapIterator<KeyT, ValueT, KeyInfoT, BucketT> iterator;
|
||||
typedef DenseMapIterator<KeyT, ValueT, KeyInfoT, BucketT, true>
|
||||
const_iterator;
|
||||
inline iterator begin() {
|
||||
// When the map is empty, avoid the overhead of AdvancePastEmptyBuckets().
|
||||
return empty() ? end() : iterator(getBuckets(), getBucketsEnd(), *this);
|
||||
// When the map is empty, avoid the overhead of advancing/retreating past
|
||||
// empty buckets.
|
||||
if (empty())
|
||||
return end();
|
||||
return makeIterator(getBuckets(), getBucketsEnd(), *this);
|
||||
}
|
||||
inline iterator end() {
|
||||
return iterator(getBucketsEnd(), getBucketsEnd(), *this, true);
|
||||
return makeIterator(getBucketsEnd(), getBucketsEnd(), *this, true);
|
||||
}
|
||||
inline const_iterator begin() const {
|
||||
return empty() ? end()
|
||||
: const_iterator(getBuckets(), getBucketsEnd(), *this);
|
||||
if (empty())
|
||||
return end();
|
||||
return makeConstIterator(getBuckets(), getBucketsEnd(), *this);
|
||||
}
|
||||
inline const_iterator end() const {
|
||||
return const_iterator(getBucketsEnd(), getBucketsEnd(), *this, true);
|
||||
return makeConstIterator(getBucketsEnd(), getBucketsEnd(), *this, true);
|
||||
}
|
||||
|
||||
bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const {
|
||||
LLVM_NODISCARD bool empty() const {
|
||||
return getNumEntries() == 0;
|
||||
}
|
||||
unsigned size() const { return getNumEntries(); }
|
||||
@@ -102,37 +112,43 @@ public:
|
||||
}
|
||||
|
||||
const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey();
|
||||
unsigned NumEntries = getNumEntries();
|
||||
for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) {
|
||||
if (!KeyInfoT::isEqual(P->getFirst(), EmptyKey)) {
|
||||
if (!KeyInfoT::isEqual(P->getFirst(), TombstoneKey)) {
|
||||
P->getSecond().~ValueT();
|
||||
--NumEntries;
|
||||
}
|
||||
if (isPodLike<KeyT>::value && isPodLike<ValueT>::value) {
|
||||
// Use a simpler loop when these are trivial types.
|
||||
for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P)
|
||||
P->getFirst() = EmptyKey;
|
||||
} else {
|
||||
unsigned NumEntries = getNumEntries();
|
||||
for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) {
|
||||
if (!KeyInfoT::isEqual(P->getFirst(), EmptyKey)) {
|
||||
if (!KeyInfoT::isEqual(P->getFirst(), TombstoneKey)) {
|
||||
P->getSecond().~ValueT();
|
||||
--NumEntries;
|
||||
}
|
||||
P->getFirst() = EmptyKey;
|
||||
}
|
||||
}
|
||||
assert(NumEntries == 0 && "Node count imbalance!");
|
||||
}
|
||||
assert(NumEntries == 0 && "Node count imbalance!");
|
||||
setNumEntries(0);
|
||||
setNumTombstones(0);
|
||||
}
|
||||
|
||||
/// Return 1 if the specified key is in the map, 0 otherwise.
|
||||
size_type count(const KeyT &Val) const {
|
||||
size_type count(const_arg_type_t<KeyT> Val) const {
|
||||
const BucketT *TheBucket;
|
||||
return LookupBucketFor(Val, TheBucket) ? 1 : 0;
|
||||
}
|
||||
|
||||
iterator find(const KeyT &Val) {
|
||||
iterator find(const_arg_type_t<KeyT> Val) {
|
||||
BucketT *TheBucket;
|
||||
if (LookupBucketFor(Val, TheBucket))
|
||||
return iterator(TheBucket, getBucketsEnd(), *this, true);
|
||||
return makeIterator(TheBucket, getBucketsEnd(), *this, true);
|
||||
return end();
|
||||
}
|
||||
const_iterator find(const KeyT &Val) const {
|
||||
const_iterator find(const_arg_type_t<KeyT> Val) const {
|
||||
const BucketT *TheBucket;
|
||||
if (LookupBucketFor(Val, TheBucket))
|
||||
return const_iterator(TheBucket, getBucketsEnd(), *this, true);
|
||||
return makeConstIterator(TheBucket, getBucketsEnd(), *this, true);
|
||||
return end();
|
||||
}
|
||||
|
||||
@@ -145,20 +161,20 @@ public:
|
||||
iterator find_as(const LookupKeyT &Val) {
|
||||
BucketT *TheBucket;
|
||||
if (LookupBucketFor(Val, TheBucket))
|
||||
return iterator(TheBucket, getBucketsEnd(), *this, true);
|
||||
return makeIterator(TheBucket, getBucketsEnd(), *this, true);
|
||||
return end();
|
||||
}
|
||||
template<class LookupKeyT>
|
||||
const_iterator find_as(const LookupKeyT &Val) const {
|
||||
const BucketT *TheBucket;
|
||||
if (LookupBucketFor(Val, TheBucket))
|
||||
return const_iterator(TheBucket, getBucketsEnd(), *this, true);
|
||||
return makeConstIterator(TheBucket, getBucketsEnd(), *this, true);
|
||||
return end();
|
||||
}
|
||||
|
||||
/// lookup - Return the entry for the specified key, or a default
|
||||
/// constructed value if no such entry exists.
|
||||
ValueT lookup(const KeyT &Val) const {
|
||||
ValueT lookup(const_arg_type_t<KeyT> Val) const {
|
||||
const BucketT *TheBucket;
|
||||
if (LookupBucketFor(Val, TheBucket))
|
||||
return TheBucket->getSecond();
|
||||
@@ -169,32 +185,51 @@ public:
|
||||
// If the key is already in the map, it returns false and doesn't update the
|
||||
// value.
|
||||
std::pair<iterator, bool> insert(const std::pair<KeyT, ValueT> &KV) {
|
||||
BucketT *TheBucket;
|
||||
if (LookupBucketFor(KV.first, TheBucket))
|
||||
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
|
||||
false); // Already in map.
|
||||
|
||||
// Otherwise, insert the new element.
|
||||
TheBucket = InsertIntoBucket(KV.first, KV.second, TheBucket);
|
||||
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
|
||||
true);
|
||||
return try_emplace(KV.first, KV.second);
|
||||
}
|
||||
|
||||
// Inserts key,value pair into the map if the key isn't already in the map.
|
||||
// If the key is already in the map, it returns false and doesn't update the
|
||||
// value.
|
||||
std::pair<iterator, bool> insert(std::pair<KeyT, ValueT> &&KV) {
|
||||
return try_emplace(std::move(KV.first), std::move(KV.second));
|
||||
}
|
||||
|
||||
// Inserts key,value pair into the map if the key isn't already in the map.
|
||||
// The value is constructed in-place if the key is not in the map, otherwise
|
||||
// it is not moved.
|
||||
template <typename... Ts>
|
||||
std::pair<iterator, bool> try_emplace(KeyT &&Key, Ts &&... Args) {
|
||||
BucketT *TheBucket;
|
||||
if (LookupBucketFor(KV.first, TheBucket))
|
||||
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
|
||||
false); // Already in map.
|
||||
if (LookupBucketFor(Key, TheBucket))
|
||||
return std::make_pair(
|
||||
makeIterator(TheBucket, getBucketsEnd(), *this, true),
|
||||
false); // Already in map.
|
||||
|
||||
// Otherwise, insert the new element.
|
||||
TheBucket = InsertIntoBucket(std::move(KV.first),
|
||||
std::move(KV.second),
|
||||
TheBucket);
|
||||
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
|
||||
true);
|
||||
TheBucket =
|
||||
InsertIntoBucket(TheBucket, std::move(Key), std::forward<Ts>(Args)...);
|
||||
return std::make_pair(
|
||||
makeIterator(TheBucket, getBucketsEnd(), *this, true),
|
||||
true);
|
||||
}
|
||||
|
||||
// Inserts key,value pair into the map if the key isn't already in the map.
|
||||
// The value is constructed in-place if the key is not in the map, otherwise
|
||||
// it is not moved.
|
||||
template <typename... Ts>
|
||||
std::pair<iterator, bool> try_emplace(const KeyT &Key, Ts &&... Args) {
|
||||
BucketT *TheBucket;
|
||||
if (LookupBucketFor(Key, TheBucket))
|
||||
return std::make_pair(
|
||||
makeIterator(TheBucket, getBucketsEnd(), *this, true),
|
||||
false); // Already in map.
|
||||
|
||||
// Otherwise, insert the new element.
|
||||
TheBucket = InsertIntoBucket(TheBucket, Key, std::forward<Ts>(Args)...);
|
||||
return std::make_pair(
|
||||
makeIterator(TheBucket, getBucketsEnd(), *this, true),
|
||||
true);
|
||||
}
|
||||
|
||||
/// Alternate version of insert() which allows a different, and possibly
|
||||
@@ -207,14 +242,16 @@ public:
|
||||
const LookupKeyT &Val) {
|
||||
BucketT *TheBucket;
|
||||
if (LookupBucketFor(Val, TheBucket))
|
||||
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
|
||||
false); // Already in map.
|
||||
return std::make_pair(
|
||||
makeIterator(TheBucket, getBucketsEnd(), *this, true),
|
||||
false); // Already in map.
|
||||
|
||||
// Otherwise, insert the new element.
|
||||
TheBucket = InsertIntoBucket(std::move(KV.first), std::move(KV.second), Val,
|
||||
TheBucket);
|
||||
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
|
||||
true);
|
||||
TheBucket = InsertIntoBucketWithLookup(TheBucket, std::move(KV.first),
|
||||
std::move(KV.second), Val);
|
||||
return std::make_pair(
|
||||
makeIterator(TheBucket, getBucketsEnd(), *this, true),
|
||||
true);
|
||||
}
|
||||
|
||||
/// insert - Range insertion of pairs.
|
||||
@@ -224,7 +261,6 @@ public:
|
||||
insert(*I);
|
||||
}
|
||||
|
||||
|
||||
bool erase(const KeyT &Val) {
|
||||
BucketT *TheBucket;
|
||||
if (!LookupBucketFor(Val, TheBucket))
|
||||
@@ -249,7 +285,7 @@ public:
|
||||
if (LookupBucketFor(Key, TheBucket))
|
||||
return *TheBucket;
|
||||
|
||||
return *InsertIntoBucket(Key, ValueT(), TheBucket);
|
||||
return *InsertIntoBucket(TheBucket, Key);
|
||||
}
|
||||
|
||||
ValueT &operator[](const KeyT &Key) {
|
||||
@@ -261,7 +297,7 @@ public:
|
||||
if (LookupBucketFor(Key, TheBucket))
|
||||
return *TheBucket;
|
||||
|
||||
return *InsertIntoBucket(std::move(Key), ValueT(), TheBucket);
|
||||
return *InsertIntoBucket(TheBucket, std::move(Key));
|
||||
}
|
||||
|
||||
ValueT &operator[](KeyT &&Key) {
|
||||
@@ -369,54 +405,83 @@ protected:
|
||||
static unsigned getHashValue(const KeyT &Val) {
|
||||
return KeyInfoT::getHashValue(Val);
|
||||
}
|
||||
|
||||
template<typename LookupKeyT>
|
||||
static unsigned getHashValue(const LookupKeyT &Val) {
|
||||
return KeyInfoT::getHashValue(Val);
|
||||
}
|
||||
|
||||
static const KeyT getEmptyKey() {
|
||||
static_assert(std::is_base_of<DenseMapBase, DerivedT>::value,
|
||||
"Must pass the derived type to this template!");
|
||||
return KeyInfoT::getEmptyKey();
|
||||
}
|
||||
|
||||
static const KeyT getTombstoneKey() {
|
||||
return KeyInfoT::getTombstoneKey();
|
||||
}
|
||||
|
||||
private:
|
||||
iterator makeIterator(BucketT *P, BucketT *E,
|
||||
DebugEpochBase &Epoch,
|
||||
bool NoAdvance=false) {
|
||||
return iterator(P, E, Epoch, NoAdvance);
|
||||
}
|
||||
|
||||
const_iterator makeConstIterator(const BucketT *P, const BucketT *E,
|
||||
const DebugEpochBase &Epoch,
|
||||
const bool NoAdvance=false) const {
|
||||
return const_iterator(P, E, Epoch, NoAdvance);
|
||||
}
|
||||
|
||||
unsigned getNumEntries() const {
|
||||
return static_cast<const DerivedT *>(this)->getNumEntries();
|
||||
}
|
||||
|
||||
void setNumEntries(unsigned Num) {
|
||||
static_cast<DerivedT *>(this)->setNumEntries(Num);
|
||||
}
|
||||
|
||||
void incrementNumEntries() {
|
||||
setNumEntries(getNumEntries() + 1);
|
||||
}
|
||||
|
||||
void decrementNumEntries() {
|
||||
setNumEntries(getNumEntries() - 1);
|
||||
}
|
||||
|
||||
unsigned getNumTombstones() const {
|
||||
return static_cast<const DerivedT *>(this)->getNumTombstones();
|
||||
}
|
||||
|
||||
void setNumTombstones(unsigned Num) {
|
||||
static_cast<DerivedT *>(this)->setNumTombstones(Num);
|
||||
}
|
||||
|
||||
void incrementNumTombstones() {
|
||||
setNumTombstones(getNumTombstones() + 1);
|
||||
}
|
||||
|
||||
void decrementNumTombstones() {
|
||||
setNumTombstones(getNumTombstones() - 1);
|
||||
}
|
||||
|
||||
const BucketT *getBuckets() const {
|
||||
return static_cast<const DerivedT *>(this)->getBuckets();
|
||||
}
|
||||
|
||||
BucketT *getBuckets() {
|
||||
return static_cast<DerivedT *>(this)->getBuckets();
|
||||
}
|
||||
|
||||
unsigned getNumBuckets() const {
|
||||
return static_cast<const DerivedT *>(this)->getNumBuckets();
|
||||
}
|
||||
|
||||
BucketT *getBucketsEnd() {
|
||||
return getBuckets() + getNumBuckets();
|
||||
}
|
||||
|
||||
const BucketT *getBucketsEnd() const {
|
||||
return getBuckets() + getNumBuckets();
|
||||
}
|
||||
@@ -429,36 +494,19 @@ private:
|
||||
static_cast<DerivedT *>(this)->shrink_and_clear();
|
||||
}
|
||||
|
||||
|
||||
BucketT *InsertIntoBucket(const KeyT &Key, const ValueT &Value,
|
||||
BucketT *TheBucket) {
|
||||
template <typename KeyArg, typename... ValueArgs>
|
||||
BucketT *InsertIntoBucket(BucketT *TheBucket, KeyArg &&Key,
|
||||
ValueArgs &&... Values) {
|
||||
TheBucket = InsertIntoBucketImpl(Key, Key, TheBucket);
|
||||
|
||||
TheBucket->getFirst() = Key;
|
||||
::new (&TheBucket->getSecond()) ValueT(Value);
|
||||
return TheBucket;
|
||||
}
|
||||
|
||||
BucketT *InsertIntoBucket(const KeyT &Key, ValueT &&Value,
|
||||
BucketT *TheBucket) {
|
||||
TheBucket = InsertIntoBucketImpl(Key, Key, TheBucket);
|
||||
|
||||
TheBucket->getFirst() = Key;
|
||||
::new (&TheBucket->getSecond()) ValueT(std::move(Value));
|
||||
return TheBucket;
|
||||
}
|
||||
|
||||
BucketT *InsertIntoBucket(KeyT &&Key, ValueT &&Value, BucketT *TheBucket) {
|
||||
TheBucket = InsertIntoBucketImpl(Key, Key, TheBucket);
|
||||
|
||||
TheBucket->getFirst() = std::move(Key);
|
||||
::new (&TheBucket->getSecond()) ValueT(std::move(Value));
|
||||
TheBucket->getFirst() = std::forward<KeyArg>(Key);
|
||||
::new (&TheBucket->getSecond()) ValueT(std::forward<ValueArgs>(Values)...);
|
||||
return TheBucket;
|
||||
}
|
||||
|
||||
template <typename LookupKeyT>
|
||||
BucketT *InsertIntoBucket(KeyT &&Key, ValueT &&Value, LookupKeyT &Lookup,
|
||||
BucketT *TheBucket) {
|
||||
BucketT *InsertIntoBucketWithLookup(BucketT *TheBucket, KeyT &&Key,
|
||||
ValueT &&Value, LookupKeyT &Lookup) {
|
||||
TheBucket = InsertIntoBucketImpl(Key, Lookup, TheBucket);
|
||||
|
||||
TheBucket->getFirst() = std::move(Key);
|
||||
@@ -530,7 +578,7 @@ private:
|
||||
|
||||
unsigned BucketNo = getHashValue(Val) & (NumBuckets-1);
|
||||
unsigned ProbeAmt = 1;
|
||||
while (1) {
|
||||
while (true) {
|
||||
const BucketT *ThisBucket = BucketsPtr + BucketNo;
|
||||
// Found Val's bucket? If so, return it.
|
||||
if (LLVM_LIKELY(KeyInfoT::isEqual(Val, ThisBucket->getFirst()))) {
|
||||
@@ -584,10 +632,11 @@ template <typename KeyT, typename ValueT,
|
||||
typename BucketT = detail::DenseMapPair<KeyT, ValueT>>
|
||||
class DenseMap : public DenseMapBase<DenseMap<KeyT, ValueT, KeyInfoT, BucketT>,
|
||||
KeyT, ValueT, KeyInfoT, BucketT> {
|
||||
friend class DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT, BucketT>;
|
||||
|
||||
// Lift some types from the dependent base class into this class for
|
||||
// simplicity of referring to them.
|
||||
typedef DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT, BucketT> BaseT;
|
||||
friend class DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT, BucketT>;
|
||||
using BaseT = DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT, BucketT>;
|
||||
|
||||
BucketT *Buckets;
|
||||
unsigned NumEntries;
|
||||
@@ -702,6 +751,7 @@ private:
|
||||
unsigned getNumEntries() const {
|
||||
return NumEntries;
|
||||
}
|
||||
|
||||
void setNumEntries(unsigned Num) {
|
||||
NumEntries = Num;
|
||||
}
|
||||
@@ -709,6 +759,7 @@ private:
|
||||
unsigned getNumTombstones() const {
|
||||
return NumTombstones;
|
||||
}
|
||||
|
||||
void setNumTombstones(unsigned Num) {
|
||||
NumTombstones = Num;
|
||||
}
|
||||
@@ -740,10 +791,14 @@ class SmallDenseMap
|
||||
: public DenseMapBase<
|
||||
SmallDenseMap<KeyT, ValueT, InlineBuckets, KeyInfoT, BucketT>, KeyT,
|
||||
ValueT, KeyInfoT, BucketT> {
|
||||
friend class DenseMapBase<SmallDenseMap, KeyT, ValueT, KeyInfoT, BucketT>;
|
||||
|
||||
// Lift some types from the dependent base class into this class for
|
||||
// simplicity of referring to them.
|
||||
typedef DenseMapBase<SmallDenseMap, KeyT, ValueT, KeyInfoT, BucketT> BaseT;
|
||||
friend class DenseMapBase<SmallDenseMap, KeyT, ValueT, KeyInfoT, BucketT>;
|
||||
using BaseT = DenseMapBase<SmallDenseMap, KeyT, ValueT, KeyInfoT, BucketT>;
|
||||
|
||||
static_assert(isPowerOf2_64(InlineBuckets),
|
||||
"InlineBuckets must be a power of 2.");
|
||||
|
||||
unsigned Small : 1;
|
||||
unsigned NumEntries : 31;
|
||||
@@ -967,14 +1022,17 @@ private:
|
||||
unsigned getNumEntries() const {
|
||||
return NumEntries;
|
||||
}
|
||||
|
||||
void setNumEntries(unsigned Num) {
|
||||
assert(Num < INT_MAX && "Cannot support more than INT_MAX entries");
|
||||
// NumEntries is hardcoded to be 31 bits wide.
|
||||
assert(Num < (1U << 31) && "Cannot support more than 1<<31 entries");
|
||||
NumEntries = Num;
|
||||
}
|
||||
|
||||
unsigned getNumTombstones() const {
|
||||
return NumTombstones;
|
||||
}
|
||||
|
||||
void setNumTombstones(unsigned Num) {
|
||||
NumTombstones = Num;
|
||||
}
|
||||
@@ -986,15 +1044,18 @@ private:
|
||||
// 'storage.buffer' static type is 'char *'.
|
||||
return reinterpret_cast<const BucketT *>(storage.buffer);
|
||||
}
|
||||
|
||||
BucketT *getInlineBuckets() {
|
||||
return const_cast<BucketT *>(
|
||||
const_cast<const SmallDenseMap *>(this)->getInlineBuckets());
|
||||
}
|
||||
|
||||
const LargeRep *getLargeRep() const {
|
||||
assert(!Small);
|
||||
// Note, same rule about aliasing as with getInlineBuckets.
|
||||
return reinterpret_cast<const LargeRep *>(storage.buffer);
|
||||
}
|
||||
|
||||
LargeRep *getLargeRep() {
|
||||
return const_cast<LargeRep *>(
|
||||
const_cast<const SmallDenseMap *>(this)->getLargeRep());
|
||||
@@ -1003,10 +1064,12 @@ private:
|
||||
const BucketT *getBuckets() const {
|
||||
return Small ? getInlineBuckets() : getLargeRep()->Buckets;
|
||||
}
|
||||
|
||||
BucketT *getBuckets() {
|
||||
return const_cast<BucketT *>(
|
||||
const_cast<const SmallDenseMap *>(this)->getBuckets());
|
||||
}
|
||||
|
||||
unsigned getNumBuckets() const {
|
||||
return Small ? InlineBuckets : getLargeRep()->NumBuckets;
|
||||
}
|
||||
@@ -1031,27 +1094,33 @@ private:
|
||||
template <typename KeyT, typename ValueT, typename KeyInfoT, typename Bucket,
|
||||
bool IsConst>
|
||||
class DenseMapIterator : DebugEpochBase::HandleBase {
|
||||
typedef DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, true> ConstIterator;
|
||||
friend class DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, true>;
|
||||
friend class DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, false>;
|
||||
|
||||
using ConstIterator = DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, true>;
|
||||
|
||||
public:
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef typename std::conditional<IsConst, const Bucket, Bucket>::type
|
||||
value_type;
|
||||
typedef value_type *pointer;
|
||||
typedef value_type &reference;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
using difference_type = ptrdiff_t;
|
||||
using value_type =
|
||||
typename std::conditional<IsConst, const Bucket, Bucket>::type;
|
||||
using pointer = value_type *;
|
||||
using reference = value_type &;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
private:
|
||||
pointer Ptr, End;
|
||||
pointer Ptr = nullptr;
|
||||
pointer End = nullptr;
|
||||
|
||||
public:
|
||||
DenseMapIterator() : Ptr(nullptr), End(nullptr) {}
|
||||
DenseMapIterator() = default;
|
||||
|
||||
DenseMapIterator(pointer Pos, pointer E, const DebugEpochBase &Epoch,
|
||||
bool NoAdvance = false)
|
||||
: DebugEpochBase::HandleBase(&Epoch), Ptr(Pos), End(E) {
|
||||
assert(isHandleInSync() && "invalid construction!");
|
||||
if (!NoAdvance) AdvancePastEmptyBuckets();
|
||||
|
||||
if (NoAdvance) return;
|
||||
AdvancePastEmptyBuckets();
|
||||
}
|
||||
|
||||
// Converting ctor from non-const iterators to const iterators. SFINAE'd out
|
||||
@@ -1100,6 +1169,7 @@ public:
|
||||
|
||||
private:
|
||||
void AdvancePastEmptyBuckets() {
|
||||
assert(Ptr <= End);
|
||||
const KeyT Empty = KeyInfoT::getEmptyKey();
|
||||
const KeyT Tombstone = KeyInfoT::getTombstoneKey();
|
||||
|
||||
@@ -1107,14 +1177,23 @@ private:
|
||||
KeyInfoT::isEqual(Ptr->getFirst(), Tombstone)))
|
||||
++Ptr;
|
||||
}
|
||||
|
||||
void RetreatPastEmptyBuckets() {
|
||||
assert(Ptr >= End);
|
||||
const KeyT Empty = KeyInfoT::getEmptyKey();
|
||||
const KeyT Tombstone = KeyInfoT::getTombstoneKey();
|
||||
|
||||
while (Ptr != End && (KeyInfoT::isEqual(Ptr[-1].getFirst(), Empty) ||
|
||||
KeyInfoT::isEqual(Ptr[-1].getFirst(), Tombstone)))
|
||||
--Ptr;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename KeyT, typename ValueT, typename KeyInfoT>
|
||||
static inline size_t
|
||||
capacity_in_bytes(const DenseMap<KeyT, ValueT, KeyInfoT> &X) {
|
||||
template <typename KeyT, typename ValueT, typename KeyInfoT>
|
||||
inline size_t capacity_in_bytes(const DenseMap<KeyT, ValueT, KeyInfoT> &X) {
|
||||
return X.getMemorySize();
|
||||
}
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif
|
||||
#endif // LLVM_ADT_DENSEMAP_H
|
||||
|
||||
@@ -11,14 +11,17 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_DENSEMAPINFO_H
|
||||
#define LLVM_ADT_DENSEMAPINFO_H
|
||||
#ifndef WPIUTIL_WPI_DENSEMAPINFO_H
|
||||
#define WPIUTIL_WPI_DENSEMAPINFO_H
|
||||
|
||||
#include "wpi/ArrayRef.h"
|
||||
#include "wpi/Hashing.h"
|
||||
#include "wpi/StringRef.h"
|
||||
#include "wpi/PointerLikeTypeTraits.h"
|
||||
#include "wpi/type_traits.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
@@ -30,36 +33,6 @@ struct DenseMapInfo {
|
||||
//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*> {
|
||||
@@ -68,15 +41,18 @@ struct DenseMapInfo<T*> {
|
||||
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; }
|
||||
};
|
||||
|
||||
@@ -85,16 +61,29 @@ 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 shorts.
|
||||
template <> struct DenseMapInfo<unsigned short> {
|
||||
static inline unsigned short getEmptyKey() { return 0xFFFF; }
|
||||
static inline unsigned short getTombstoneKey() { return 0xFFFF - 1; }
|
||||
static unsigned getHashValue(const unsigned short &Val) { return Val * 37U; }
|
||||
|
||||
static bool isEqual(const unsigned short &LHS, const unsigned short &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;
|
||||
}
|
||||
@@ -104,9 +93,11 @@ template<> struct DenseMapInfo<unsigned> {
|
||||
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;
|
||||
}
|
||||
@@ -116,20 +107,31 @@ template<> struct DenseMapInfo<unsigned long> {
|
||||
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 shorts.
|
||||
template <> struct DenseMapInfo<short> {
|
||||
static inline short getEmptyKey() { return 0x7FFF; }
|
||||
static inline short getTombstoneKey() { return -0x7FFF - 1; }
|
||||
static unsigned getHashValue(const short &Val) { return Val * 37U; }
|
||||
static bool isEqual(const short &LHS, const short &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;
|
||||
}
|
||||
@@ -140,10 +142,13 @@ 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;
|
||||
}
|
||||
@@ -153,9 +158,11 @@ template<> struct DenseMapInfo<long> {
|
||||
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;
|
||||
@@ -164,19 +171,21 @@ template<> struct DenseMapInfo<long long> {
|
||||
|
||||
// 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;
|
||||
struct DenseMapInfo<std::pair<T, U>> {
|
||||
using Pair = std::pair<T, U>;
|
||||
using FirstInfo = DenseMapInfo<T>;
|
||||
using SecondInfo = DenseMapInfo<U>;
|
||||
|
||||
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);
|
||||
@@ -190,6 +199,7 @@ struct DenseMapInfo<std::pair<T, U> > {
|
||||
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);
|
||||
@@ -202,16 +212,19 @@ template <> struct DenseMapInfo<StringRef> {
|
||||
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();
|
||||
@@ -227,16 +240,19 @@ template <typename T> struct DenseMapInfo<ArrayRef<T>> {
|
||||
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();
|
||||
@@ -248,4 +264,4 @@ template <typename T> struct DenseMapInfo<ArrayRef<T>> {
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif
|
||||
#endif // LLVM_ADT_DENSEMAPINFO_H
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_EPOCH_TRACKER_H
|
||||
#define LLVM_ADT_EPOCH_TRACKER_H
|
||||
#ifndef WPIUTIL_WPI_EPOCH_TRACKER_H
|
||||
#define WPIUTIL_WPI_EPOCH_TRACKER_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
|
||||
#else
|
||||
|
||||
/// \brief A base class for data structure classes wishing to make iterators
|
||||
/// 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.
|
||||
///
|
||||
@@ -52,15 +52,15 @@ class DebugEpochBase {
|
||||
public:
|
||||
DebugEpochBase() : Epoch(0) {}
|
||||
|
||||
/// \brief Calling incrementEpoch invalidates all handles pointing into the
|
||||
/// Calling incrementEpoch invalidates all handles pointing into the
|
||||
/// calling instance.
|
||||
void incrementEpoch() { ++Epoch; }
|
||||
|
||||
/// \brief The destructor calls incrementEpoch to make use-after-free bugs
|
||||
/// 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
|
||||
/// 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.
|
||||
///
|
||||
@@ -78,12 +78,12 @@ public:
|
||||
explicit HandleBase(const DebugEpochBase *Parent)
|
||||
: EpochAddress(&Parent->Epoch), EpochAtCreation(Parent->Epoch) {}
|
||||
|
||||
/// \brief Returns true if the DebugEpochBase this Handle is linked to has
|
||||
/// 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
|
||||
/// 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; }
|
||||
|
||||
291
wpiutil/src/main/native/include/wpi/ErrorOr.h
Normal file
291
wpiutil/src/main/native/include/wpi/ErrorOr.h
Normal file
@@ -0,0 +1,291 @@
|
||||
//===- llvm/Support/ErrorOr.h - Error Smart Pointer -------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
///
|
||||
/// Provides ErrorOr<T> smart pointer.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_ERROROR_H
|
||||
#define WPIUTIL_WPI_ERROROR_H
|
||||
|
||||
#include "wpi/AlignOf.h"
|
||||
#include <cassert>
|
||||
#include <system_error>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// Stores a reference that can be changed.
|
||||
template <typename T>
|
||||
class ReferenceStorage {
|
||||
T *Storage;
|
||||
|
||||
public:
|
||||
ReferenceStorage(T &Ref) : Storage(&Ref) {}
|
||||
|
||||
operator T &() const { return *Storage; }
|
||||
T &get() const { return *Storage; }
|
||||
};
|
||||
|
||||
/// Represents either an error or a value T.
|
||||
///
|
||||
/// ErrorOr<T> is a pointer-like class that represents the result of an
|
||||
/// operation. The result is either an error, or a value of type T. This is
|
||||
/// designed to emulate the usage of returning a pointer where nullptr indicates
|
||||
/// failure. However instead of just knowing that the operation failed, we also
|
||||
/// have an error_code and optional user data that describes why it failed.
|
||||
///
|
||||
/// It is used like the following.
|
||||
/// \code
|
||||
/// ErrorOr<Buffer> getBuffer();
|
||||
///
|
||||
/// auto buffer = getBuffer();
|
||||
/// if (error_code ec = buffer.getError())
|
||||
/// return ec;
|
||||
/// buffer->write("adena");
|
||||
/// \endcode
|
||||
///
|
||||
///
|
||||
/// Implicit conversion to bool returns true if there is a usable value. The
|
||||
/// unary * and -> operators provide pointer like access to the value. Accessing
|
||||
/// the value when there is an error has undefined behavior.
|
||||
///
|
||||
/// When T is a reference type the behavior is slightly different. The reference
|
||||
/// is held in a std::reference_wrapper<std::remove_reference<T>::type>, and
|
||||
/// there is special handling to make operator -> work as if T was not a
|
||||
/// reference.
|
||||
///
|
||||
/// T cannot be a rvalue reference.
|
||||
template<class T>
|
||||
class ErrorOr {
|
||||
template <class OtherT> friend class ErrorOr;
|
||||
|
||||
static const bool isRef = std::is_reference<T>::value;
|
||||
|
||||
using wrap = ReferenceStorage<typename std::remove_reference<T>::type>;
|
||||
|
||||
public:
|
||||
using storage_type = typename std::conditional<isRef, wrap, T>::type;
|
||||
|
||||
private:
|
||||
using reference = typename std::remove_reference<T>::type &;
|
||||
using const_reference = const typename std::remove_reference<T>::type &;
|
||||
using pointer = typename std::remove_reference<T>::type *;
|
||||
using const_pointer = const typename std::remove_reference<T>::type *;
|
||||
|
||||
public:
|
||||
template <class E>
|
||||
ErrorOr(E ErrorCode,
|
||||
typename std::enable_if<std::is_error_code_enum<E>::value ||
|
||||
std::is_error_condition_enum<E>::value,
|
||||
void *>::type = nullptr)
|
||||
: HasError(true) {
|
||||
new (getErrorStorage()) std::error_code(make_error_code(ErrorCode));
|
||||
}
|
||||
|
||||
ErrorOr(std::error_code EC) : HasError(true) {
|
||||
new (getErrorStorage()) std::error_code(EC);
|
||||
}
|
||||
|
||||
template <class OtherT>
|
||||
ErrorOr(OtherT &&Val,
|
||||
typename std::enable_if<std::is_convertible<OtherT, T>::value>::type
|
||||
* = nullptr)
|
||||
: HasError(false) {
|
||||
new (getStorage()) storage_type(std::forward<OtherT>(Val));
|
||||
}
|
||||
|
||||
ErrorOr(const ErrorOr &Other) {
|
||||
copyConstruct(Other);
|
||||
}
|
||||
|
||||
template <class OtherT>
|
||||
ErrorOr(
|
||||
const ErrorOr<OtherT> &Other,
|
||||
typename std::enable_if<std::is_convertible<OtherT, T>::value>::type * =
|
||||
nullptr) {
|
||||
copyConstruct(Other);
|
||||
}
|
||||
|
||||
template <class OtherT>
|
||||
explicit ErrorOr(
|
||||
const ErrorOr<OtherT> &Other,
|
||||
typename std::enable_if<
|
||||
!std::is_convertible<OtherT, const T &>::value>::type * = nullptr) {
|
||||
copyConstruct(Other);
|
||||
}
|
||||
|
||||
ErrorOr(ErrorOr &&Other) {
|
||||
moveConstruct(std::move(Other));
|
||||
}
|
||||
|
||||
template <class OtherT>
|
||||
ErrorOr(
|
||||
ErrorOr<OtherT> &&Other,
|
||||
typename std::enable_if<std::is_convertible<OtherT, T>::value>::type * =
|
||||
nullptr) {
|
||||
moveConstruct(std::move(Other));
|
||||
}
|
||||
|
||||
// This might eventually need SFINAE but it's more complex than is_convertible
|
||||
// & I'm too lazy to write it right now.
|
||||
template <class OtherT>
|
||||
explicit ErrorOr(
|
||||
ErrorOr<OtherT> &&Other,
|
||||
typename std::enable_if<!std::is_convertible<OtherT, T>::value>::type * =
|
||||
nullptr) {
|
||||
moveConstruct(std::move(Other));
|
||||
}
|
||||
|
||||
ErrorOr &operator=(const ErrorOr &Other) {
|
||||
copyAssign(Other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ErrorOr &operator=(ErrorOr &&Other) {
|
||||
moveAssign(std::move(Other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
~ErrorOr() {
|
||||
if (!HasError)
|
||||
getStorage()->~storage_type();
|
||||
}
|
||||
|
||||
/// Return false if there is an error.
|
||||
explicit operator bool() const {
|
||||
return !HasError;
|
||||
}
|
||||
|
||||
reference get() { return *getStorage(); }
|
||||
const_reference get() const { return const_cast<ErrorOr<T> *>(this)->get(); }
|
||||
|
||||
std::error_code getError() const {
|
||||
return HasError ? *getErrorStorage() : std::error_code();
|
||||
}
|
||||
|
||||
pointer operator ->() {
|
||||
return toPointer(getStorage());
|
||||
}
|
||||
|
||||
const_pointer operator->() const { return toPointer(getStorage()); }
|
||||
|
||||
reference operator *() {
|
||||
return *getStorage();
|
||||
}
|
||||
|
||||
const_reference operator*() const { return *getStorage(); }
|
||||
|
||||
private:
|
||||
template <class OtherT>
|
||||
void copyConstruct(const ErrorOr<OtherT> &Other) {
|
||||
if (!Other.HasError) {
|
||||
// Get the other value.
|
||||
HasError = false;
|
||||
new (getStorage()) storage_type(*Other.getStorage());
|
||||
} else {
|
||||
// Get other's error.
|
||||
HasError = true;
|
||||
new (getErrorStorage()) std::error_code(Other.getError());
|
||||
}
|
||||
}
|
||||
|
||||
template <class T1>
|
||||
static bool compareThisIfSameType(const T1 &a, const T1 &b) {
|
||||
return &a == &b;
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
static bool compareThisIfSameType(const T1 &a, const T2 &b) {
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class OtherT>
|
||||
void copyAssign(const ErrorOr<OtherT> &Other) {
|
||||
if (compareThisIfSameType(*this, Other))
|
||||
return;
|
||||
|
||||
this->~ErrorOr();
|
||||
new (this) ErrorOr(Other);
|
||||
}
|
||||
|
||||
template <class OtherT>
|
||||
void moveConstruct(ErrorOr<OtherT> &&Other) {
|
||||
if (!Other.HasError) {
|
||||
// Get the other value.
|
||||
HasError = false;
|
||||
new (getStorage()) storage_type(std::move(*Other.getStorage()));
|
||||
} else {
|
||||
// Get other's error.
|
||||
HasError = true;
|
||||
new (getErrorStorage()) std::error_code(Other.getError());
|
||||
}
|
||||
}
|
||||
|
||||
template <class OtherT>
|
||||
void moveAssign(ErrorOr<OtherT> &&Other) {
|
||||
if (compareThisIfSameType(*this, Other))
|
||||
return;
|
||||
|
||||
this->~ErrorOr();
|
||||
new (this) ErrorOr(std::move(Other));
|
||||
}
|
||||
|
||||
pointer toPointer(pointer Val) {
|
||||
return Val;
|
||||
}
|
||||
|
||||
const_pointer toPointer(const_pointer Val) const { return Val; }
|
||||
|
||||
pointer toPointer(wrap *Val) {
|
||||
return &Val->get();
|
||||
}
|
||||
|
||||
const_pointer toPointer(const wrap *Val) const { return &Val->get(); }
|
||||
|
||||
storage_type *getStorage() {
|
||||
assert(!HasError && "Cannot get value when an error exists!");
|
||||
return reinterpret_cast<storage_type*>(TStorage.buffer);
|
||||
}
|
||||
|
||||
const storage_type *getStorage() const {
|
||||
assert(!HasError && "Cannot get value when an error exists!");
|
||||
return reinterpret_cast<const storage_type*>(TStorage.buffer);
|
||||
}
|
||||
|
||||
std::error_code *getErrorStorage() {
|
||||
assert(HasError && "Cannot get error when a value exists!");
|
||||
return reinterpret_cast<std::error_code *>(ErrorStorage.buffer);
|
||||
}
|
||||
|
||||
const std::error_code *getErrorStorage() const {
|
||||
return const_cast<ErrorOr<T> *>(this)->getErrorStorage();
|
||||
}
|
||||
|
||||
union {
|
||||
AlignedCharArrayUnion<storage_type> TStorage;
|
||||
AlignedCharArrayUnion<std::error_code> ErrorStorage;
|
||||
};
|
||||
bool HasError : 1;
|
||||
};
|
||||
|
||||
template <class T, class E>
|
||||
typename std::enable_if<std::is_error_code_enum<E>::value ||
|
||||
std::is_error_condition_enum<E>::value,
|
||||
bool>::type
|
||||
operator==(const ErrorOr<T> &Err, E Code) {
|
||||
return Err.getError() == Code;
|
||||
}
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // LLVM_SUPPORT_ERROROR_H
|
||||
@@ -24,21 +24,25 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_FILESYSTEM_H
|
||||
#define LLVM_SUPPORT_FILESYSTEM_H
|
||||
#ifndef WPIUTIL_WPI_FILESYSTEM_H
|
||||
#define WPIUTIL_WPI_FILESYSTEM_H
|
||||
|
||||
#include "wpi/IntrusiveRefCntPtr.h"
|
||||
#include "wpi/SmallString.h"
|
||||
#include "wpi/StringRef.h"
|
||||
#include "wpi/Twine.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "wpi/ErrorOr.h"
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
#include <memory>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
namespace wpi {
|
||||
namespace sys {
|
||||
namespace fs {
|
||||
@@ -78,6 +82,7 @@ enum perms {
|
||||
set_uid_on_exe = 04000,
|
||||
set_gid_on_exe = 02000,
|
||||
sticky_bit = 01000,
|
||||
all_perms = all_all | set_uid_on_exe | set_gid_on_exe | sticky_bit,
|
||||
perms_not_known = 0xFFFF
|
||||
};
|
||||
|
||||
@@ -99,8 +104,9 @@ inline perms &operator&=(perms &l, perms r) {
|
||||
return l;
|
||||
}
|
||||
inline perms operator~(perms x) {
|
||||
// Avoid UB by explicitly truncating the (unsigned) ~ result.
|
||||
return static_cast<perms>(
|
||||
static_cast<unsigned short>(~static_cast<unsigned short>(x)));
|
||||
static_cast<unsigned short>(~static_cast<unsigned short>(x)));
|
||||
}
|
||||
|
||||
class UniqueID {
|
||||
@@ -110,6 +116,7 @@ class UniqueID {
|
||||
public:
|
||||
UniqueID() = default;
|
||||
UniqueID(uint64_t Device, uint64_t File) : Device(Device), File(File) {}
|
||||
|
||||
bool operator==(const UniqueID &Other) const {
|
||||
return Device == Other.Device && File == Other.File;
|
||||
}
|
||||
@@ -117,99 +124,75 @@ public:
|
||||
bool operator<(const UniqueID &Other) const {
|
||||
return std::tie(Device, File) < std::tie(Other.Device, Other.File);
|
||||
}
|
||||
|
||||
uint64_t getDevice() const { return Device; }
|
||||
uint64_t getFile() const { return File; }
|
||||
};
|
||||
|
||||
/// file_status - Represents the result of a call to stat and friends. It has
|
||||
/// a platform-specific member to store the result.
|
||||
class file_status
|
||||
{
|
||||
#ifdef _WIN32
|
||||
uint32_t LastAccessedTimeHigh;
|
||||
uint32_t LastAccessedTimeLow;
|
||||
uint32_t LastWriteTimeHigh;
|
||||
uint32_t LastWriteTimeLow;
|
||||
uint32_t VolumeSerialNumber;
|
||||
uint32_t FileSizeHigh;
|
||||
uint32_t FileSizeLow;
|
||||
uint32_t FileIndexHigh;
|
||||
uint32_t FileIndexLow;
|
||||
/// Represents the result of a call to directory_iterator::status(). This is a
|
||||
/// subset of the information returned by a regular sys::fs::status() call, and
|
||||
/// represents the information provided by Windows FileFirstFile/FindNextFile.
|
||||
class basic_file_status {
|
||||
protected:
|
||||
#ifndef _WIN32
|
||||
time_t fs_st_atime = 0;
|
||||
time_t fs_st_mtime = 0;
|
||||
uid_t fs_st_uid = 0;
|
||||
gid_t fs_st_gid = 0;
|
||||
off_t fs_st_size = 0;
|
||||
#else
|
||||
dev_t fs_st_dev;
|
||||
ino_t fs_st_ino;
|
||||
time_t fs_st_atime;
|
||||
time_t fs_st_mtime;
|
||||
uid_t fs_st_uid;
|
||||
gid_t fs_st_gid;
|
||||
off_t fs_st_size;
|
||||
uint32_t LastAccessedTimeHigh = 0;
|
||||
uint32_t LastAccessedTimeLow = 0;
|
||||
uint32_t LastWriteTimeHigh = 0;
|
||||
uint32_t LastWriteTimeLow = 0;
|
||||
uint32_t FileSizeHigh = 0;
|
||||
uint32_t FileSizeLow = 0;
|
||||
#endif
|
||||
friend bool equivalent(file_status A, file_status B);
|
||||
file_type Type;
|
||||
perms Perms;
|
||||
file_type Type = file_type::status_error;
|
||||
perms Perms = perms_not_known;
|
||||
|
||||
public:
|
||||
#ifdef _WIN32
|
||||
file_status()
|
||||
: LastAccessedTimeHigh(0), LastAccessedTimeLow(0), LastWriteTimeHigh(0),
|
||||
LastWriteTimeLow(0), VolumeSerialNumber(0), FileSizeHigh(0),
|
||||
FileSizeLow(0), FileIndexHigh(0), FileIndexLow(0),
|
||||
Type(file_type::status_error), Perms(perms_not_known) {}
|
||||
basic_file_status() = default;
|
||||
|
||||
file_status(file_type Type)
|
||||
: LastAccessedTimeHigh(0), LastAccessedTimeLow(0), LastWriteTimeHigh(0),
|
||||
LastWriteTimeLow(0), VolumeSerialNumber(0), FileSizeHigh(0),
|
||||
FileSizeLow(0), FileIndexHigh(0), FileIndexLow(0), Type(Type),
|
||||
Perms(perms_not_known) {}
|
||||
explicit basic_file_status(file_type Type) : Type(Type) {}
|
||||
|
||||
file_status(file_type Type, uint32_t LastAccessTimeHigh,
|
||||
uint32_t LastAccessTimeLow, uint32_t LastWriteTimeHigh,
|
||||
uint32_t LastWriteTimeLow, uint32_t VolumeSerialNumber,
|
||||
uint32_t FileSizeHigh, uint32_t FileSizeLow,
|
||||
uint32_t FileIndexHigh, uint32_t FileIndexLow)
|
||||
: LastAccessedTimeHigh(LastAccessTimeHigh), LastAccessedTimeLow(LastAccessTimeLow),
|
||||
LastWriteTimeHigh(LastWriteTimeHigh),
|
||||
LastWriteTimeLow(LastWriteTimeLow),
|
||||
VolumeSerialNumber(VolumeSerialNumber), FileSizeHigh(FileSizeHigh),
|
||||
FileSizeLow(FileSizeLow), FileIndexHigh(FileIndexHigh),
|
||||
FileIndexLow(FileIndexLow), Type(Type), Perms(perms_not_known) {}
|
||||
#ifndef _WIN32
|
||||
basic_file_status(file_type Type, perms Perms, time_t ATime, time_t MTime,
|
||||
uid_t UID, gid_t GID, off_t Size)
|
||||
: fs_st_atime(ATime), fs_st_mtime(MTime), fs_st_uid(UID), fs_st_gid(GID),
|
||||
fs_st_size(Size), Type(Type), Perms(Perms) {}
|
||||
#else
|
||||
file_status()
|
||||
: fs_st_dev(0), fs_st_ino(0), fs_st_atime(0), fs_st_mtime(0),
|
||||
fs_st_uid(0), fs_st_gid(0), fs_st_size(0),
|
||||
Type(file_type::status_error), Perms(perms_not_known) {}
|
||||
|
||||
file_status(file_type Type)
|
||||
: fs_st_dev(0), fs_st_ino(0), fs_st_atime(0), fs_st_mtime(0),
|
||||
fs_st_uid(0), fs_st_gid(0), fs_st_size(0), Type(Type),
|
||||
Perms(perms_not_known) {}
|
||||
|
||||
file_status(file_type Type, perms Perms, dev_t Dev, ino_t Ino, time_t ATime,
|
||||
time_t MTime, uid_t UID, gid_t GID, off_t Size)
|
||||
: fs_st_dev(Dev), fs_st_ino(Ino), fs_st_atime(ATime), fs_st_mtime(MTime),
|
||||
fs_st_uid(UID), fs_st_gid(GID), fs_st_size(Size), Type(Type),
|
||||
Perms(Perms) {}
|
||||
basic_file_status(file_type Type, perms Perms, uint32_t LastAccessTimeHigh,
|
||||
uint32_t LastAccessTimeLow, uint32_t LastWriteTimeHigh,
|
||||
uint32_t LastWriteTimeLow, uint32_t FileSizeHigh,
|
||||
uint32_t FileSizeLow)
|
||||
: LastAccessedTimeHigh(LastAccessTimeHigh),
|
||||
LastAccessedTimeLow(LastAccessTimeLow),
|
||||
LastWriteTimeHigh(LastWriteTimeHigh),
|
||||
LastWriteTimeLow(LastWriteTimeLow), FileSizeHigh(FileSizeHigh),
|
||||
FileSizeLow(FileSizeLow), Type(Type), Perms(Perms) {}
|
||||
#endif
|
||||
|
||||
// getters
|
||||
file_type type() const { return Type; }
|
||||
perms permissions() const { return Perms; }
|
||||
UniqueID getUniqueID() const;
|
||||
|
||||
#ifdef _WIN32
|
||||
uint32_t getUser() const {
|
||||
return 9999; // Not applicable to Windows, so...
|
||||
}
|
||||
uint32_t getGroup() const {
|
||||
return 9999; // Not applicable to Windows, so...
|
||||
}
|
||||
uint64_t getSize() const {
|
||||
return (uint64_t(FileSizeHigh) << 32) + FileSizeLow;
|
||||
}
|
||||
#else
|
||||
#ifndef _WIN32
|
||||
uint32_t getUser() const { return fs_st_uid; }
|
||||
uint32_t getGroup() const { return fs_st_gid; }
|
||||
uint64_t getSize() const { return fs_st_size; }
|
||||
#else
|
||||
uint32_t getUser() const {
|
||||
return 9999; // Not applicable to Windows, so...
|
||||
}
|
||||
|
||||
uint32_t getGroup() const {
|
||||
return 9999; // Not applicable to Windows, so...
|
||||
}
|
||||
|
||||
uint64_t getSize() const {
|
||||
return (uint64_t(FileSizeHigh) << 32) + FileSizeLow;
|
||||
}
|
||||
#endif
|
||||
|
||||
// setters
|
||||
@@ -217,11 +200,54 @@ public:
|
||||
void permissions(perms p) { Perms = p; }
|
||||
};
|
||||
|
||||
/// Represents the result of a call to sys::fs::status().
|
||||
class file_status : public basic_file_status {
|
||||
friend bool equivalent(file_status A, file_status B);
|
||||
|
||||
#ifndef _WIN32
|
||||
dev_t fs_st_dev = 0;
|
||||
nlink_t fs_st_nlinks = 0;
|
||||
ino_t fs_st_ino = 0;
|
||||
#else
|
||||
uint32_t NumLinks = 0;
|
||||
uint32_t VolumeSerialNumber = 0;
|
||||
uint32_t FileIndexHigh = 0;
|
||||
uint32_t FileIndexLow = 0;
|
||||
#endif
|
||||
|
||||
public:
|
||||
file_status() = default;
|
||||
|
||||
explicit file_status(file_type Type) : basic_file_status(Type) {}
|
||||
|
||||
#ifndef _WIN32
|
||||
file_status(file_type Type, perms Perms, dev_t Dev, nlink_t Links, ino_t Ino,
|
||||
time_t ATime, time_t MTime, uid_t UID, gid_t GID, off_t Size)
|
||||
: basic_file_status(Type, Perms, ATime, MTime, UID, GID, Size),
|
||||
fs_st_dev(Dev), fs_st_nlinks(Links), fs_st_ino(Ino) {}
|
||||
#else
|
||||
file_status(file_type Type, perms Perms, uint32_t LinkCount,
|
||||
uint32_t LastAccessTimeHigh, uint32_t LastAccessTimeLow,
|
||||
uint32_t LastWriteTimeHigh, uint32_t LastWriteTimeLow,
|
||||
uint32_t VolumeSerialNumber, uint32_t FileSizeHigh,
|
||||
uint32_t FileSizeLow, uint32_t FileIndexHigh,
|
||||
uint32_t FileIndexLow)
|
||||
: basic_file_status(Type, Perms, LastAccessTimeHigh, LastAccessTimeLow,
|
||||
LastWriteTimeHigh, LastWriteTimeLow, FileSizeHigh,
|
||||
FileSizeLow),
|
||||
NumLinks(LinkCount), VolumeSerialNumber(VolumeSerialNumber),
|
||||
FileIndexHigh(FileIndexHigh), FileIndexLow(FileIndexLow) {}
|
||||
#endif
|
||||
|
||||
UniqueID getUniqueID() const;
|
||||
uint32_t getLinkCount() const;
|
||||
};
|
||||
|
||||
/// @}
|
||||
/// @name Physical Operators
|
||||
/// @{
|
||||
|
||||
/// @brief Make \a path an absolute path.
|
||||
/// Make \a path an absolute path.
|
||||
///
|
||||
/// Makes \a path absolute using the \a current_directory if it is not already.
|
||||
/// An empty \a path will result in the \a current_directory.
|
||||
@@ -235,7 +261,7 @@ public:
|
||||
std::error_code make_absolute(const Twine ¤t_directory,
|
||||
SmallVectorImpl<char> &path);
|
||||
|
||||
/// @brief Make \a path an absolute path.
|
||||
/// Make \a path an absolute path.
|
||||
///
|
||||
/// Makes \a path absolute using the current directory if it is not already. An
|
||||
/// empty \a path will result in the current directory.
|
||||
@@ -248,7 +274,7 @@ std::error_code make_absolute(const Twine ¤t_directory,
|
||||
/// platform-specific error_code.
|
||||
std::error_code make_absolute(SmallVectorImpl<char> &path);
|
||||
|
||||
/// @brief Get the current path.
|
||||
/// Get the current path.
|
||||
///
|
||||
/// @param result Holds the current path on return.
|
||||
/// @returns errc::success if the current path has been stored in result,
|
||||
@@ -259,23 +285,23 @@ std::error_code current_path(SmallVectorImpl<char> &result);
|
||||
/// @name Physical Observers
|
||||
/// @{
|
||||
|
||||
/// @brief Does file exist?
|
||||
/// Does file exist?
|
||||
///
|
||||
/// @param status A file_status previously returned from stat.
|
||||
/// @param status A basic_file_status previously returned from stat.
|
||||
/// @returns True if the file represented by status exists, false if it does
|
||||
/// not.
|
||||
bool exists(file_status status);
|
||||
bool exists(const basic_file_status &status);
|
||||
|
||||
enum class AccessMode { Exist, Write, Execute };
|
||||
|
||||
/// @brief Can the file be accessed?
|
||||
/// Can the file be accessed?
|
||||
///
|
||||
/// @param Path Input path.
|
||||
/// @returns errc::success if the path can be accessed, otherwise a
|
||||
/// platform-specific error_code.
|
||||
std::error_code access(const Twine &Path, AccessMode Mode);
|
||||
|
||||
/// @brief Does file exist?
|
||||
/// Does file exist?
|
||||
///
|
||||
/// @param Path Input path.
|
||||
/// @returns True if it exists, false otherwise.
|
||||
@@ -283,7 +309,7 @@ inline bool exists(const Twine &Path) {
|
||||
return !access(Path, AccessMode::Exist);
|
||||
}
|
||||
|
||||
/// @brief Can we write this file?
|
||||
/// Can we write this file?
|
||||
///
|
||||
/// @param Path Input path.
|
||||
/// @returns True if we can write to it, false otherwise.
|
||||
@@ -291,7 +317,7 @@ inline bool can_write(const Twine &Path) {
|
||||
return !access(Path, AccessMode::Write);
|
||||
}
|
||||
|
||||
/// @brief Do file_status's represent the same thing?
|
||||
/// Do file_status's represent the same thing?
|
||||
///
|
||||
/// @param A Input file_status.
|
||||
/// @param B Input file_status.
|
||||
@@ -302,7 +328,7 @@ inline bool can_write(const Twine &Path) {
|
||||
/// otherwise.
|
||||
bool equivalent(file_status A, file_status B);
|
||||
|
||||
/// @brief Do paths represent the same thing?
|
||||
/// Do paths represent the same thing?
|
||||
///
|
||||
/// assert(status_known(A) || status_known(B));
|
||||
///
|
||||
@@ -314,51 +340,51 @@ bool equivalent(file_status A, file_status B);
|
||||
/// platform-specific error_code.
|
||||
std::error_code equivalent(const Twine &A, const Twine &B, bool &result);
|
||||
|
||||
/// @brief Simpler version of equivalent for clients that don't need to
|
||||
/// Simpler version of equivalent for clients that don't need to
|
||||
/// differentiate between an error and false.
|
||||
inline bool equivalent(const Twine &A, const Twine &B) {
|
||||
bool result;
|
||||
return !equivalent(A, B, result) && result;
|
||||
}
|
||||
|
||||
/// @brief Does status represent a directory?
|
||||
/// Does status represent a directory?
|
||||
///
|
||||
/// @param status A file_status previously returned from status.
|
||||
/// @param status A basic_file_status previously returned from status.
|
||||
/// @returns status.type() == file_type::directory_file.
|
||||
bool is_directory(file_status status);
|
||||
bool is_directory(const basic_file_status &status);
|
||||
|
||||
/// @brief Is path a directory?
|
||||
/// Is path a directory?
|
||||
///
|
||||
/// @param path Input path.
|
||||
/// @param result Set to true if \a path is a directory, false if it is not.
|
||||
/// Undefined otherwise.
|
||||
/// @param result Set to true if \a path is a directory (after following
|
||||
/// symlinks, false if it is not. Undefined otherwise.
|
||||
/// @returns errc::success if result has been successfully set, otherwise a
|
||||
/// platform-specific error_code.
|
||||
std::error_code is_directory(const Twine &path, bool &result);
|
||||
|
||||
/// @brief Simpler version of is_directory for clients that don't need to
|
||||
/// Simpler version of is_directory for clients that don't need to
|
||||
/// differentiate between an error and false.
|
||||
inline bool is_directory(const Twine &Path) {
|
||||
bool Result;
|
||||
return !is_directory(Path, Result) && Result;
|
||||
}
|
||||
|
||||
/// @brief Does status represent a regular file?
|
||||
/// Does status represent a regular file?
|
||||
///
|
||||
/// @param status A file_status previously returned from status.
|
||||
/// @param status A basic_file_status previously returned from status.
|
||||
/// @returns status_known(status) && status.type() == file_type::regular_file.
|
||||
bool is_regular_file(file_status status);
|
||||
bool is_regular_file(const basic_file_status &status);
|
||||
|
||||
/// @brief Is path a regular file?
|
||||
/// Is path a regular file?
|
||||
///
|
||||
/// @param path Input path.
|
||||
/// @param result Set to true if \a path is a regular file, false if it is not.
|
||||
/// Undefined otherwise.
|
||||
/// @param result Set to true if \a path is a regular file (after following
|
||||
/// symlinks), false if it is not. Undefined otherwise.
|
||||
/// @returns errc::success if result has been successfully set, otherwise a
|
||||
/// platform-specific error_code.
|
||||
std::error_code is_regular_file(const Twine &path, bool &result);
|
||||
|
||||
/// @brief Simpler version of is_regular_file for clients that don't need to
|
||||
/// Simpler version of is_regular_file for clients that don't need to
|
||||
/// differentiate between an error and false.
|
||||
inline bool is_regular_file(const Twine &Path) {
|
||||
bool Result;
|
||||
@@ -367,14 +393,38 @@ inline bool is_regular_file(const Twine &Path) {
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// @brief Does this status represent something that exists but is not a
|
||||
/// directory, regular file, or symlink?
|
||||
/// Does status represent a symlink file?
|
||||
///
|
||||
/// @param status A file_status previously returned from status.
|
||||
/// @returns exists(s) && !is_regular_file(s) && !is_directory(s)
|
||||
bool is_other(file_status status);
|
||||
/// @param status A basic_file_status previously returned from status.
|
||||
/// @returns status_known(status) && status.type() == file_type::symlink_file.
|
||||
bool is_symlink_file(const basic_file_status &status);
|
||||
|
||||
/// @brief Is path something that exists but is not a directory,
|
||||
/// Is path a symlink file?
|
||||
///
|
||||
/// @param path Input path.
|
||||
/// @param result Set to true if \a path is a symlink file, false if it is not.
|
||||
/// Undefined otherwise.
|
||||
/// @returns errc::success if result has been successfully set, otherwise a
|
||||
/// platform-specific error_code.
|
||||
std::error_code is_symlink_file(const Twine &path, bool &result);
|
||||
|
||||
/// Simpler version of is_symlink_file for clients that don't need to
|
||||
/// differentiate between an error and false.
|
||||
inline bool is_symlink_file(const Twine &Path) {
|
||||
bool Result;
|
||||
if (is_symlink_file(Path, Result))
|
||||
return false;
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// Does this status represent something that exists but is not a
|
||||
/// directory or regular file?
|
||||
///
|
||||
/// @param status A basic_file_status previously returned from status.
|
||||
/// @returns exists(s) && !is_regular_file(s) && !is_directory(s)
|
||||
bool is_other(const basic_file_status &status);
|
||||
|
||||
/// Is path something that exists but is not a directory,
|
||||
/// regular file, or symlink?
|
||||
///
|
||||
/// @param path Input path.
|
||||
@@ -384,24 +434,27 @@ bool is_other(file_status status);
|
||||
/// platform-specific error_code.
|
||||
std::error_code is_other(const Twine &path, bool &result);
|
||||
|
||||
/// @brief Get file status as if by POSIX stat().
|
||||
/// Get file status as if by POSIX stat().
|
||||
///
|
||||
/// @param path Input path.
|
||||
/// @param result Set to the file status.
|
||||
/// @param follow When true, follows symlinks. Otherwise, the symlink itself is
|
||||
/// statted.
|
||||
/// @returns errc::success if result has been successfully set, otherwise a
|
||||
/// platform-specific error_code.
|
||||
std::error_code status(const Twine &path, file_status &result);
|
||||
std::error_code status(const Twine &path, file_status &result,
|
||||
bool follow = true);
|
||||
|
||||
/// @brief A version for when a file descriptor is already available.
|
||||
/// A version for when a file descriptor is already available.
|
||||
std::error_code status(int FD, file_status &Result);
|
||||
|
||||
/// @brief Is status available?
|
||||
/// Is status available?
|
||||
///
|
||||
/// @param s Input file status.
|
||||
/// @returns True if status() != status_error.
|
||||
bool status_known(file_status s);
|
||||
bool status_known(const basic_file_status &s);
|
||||
|
||||
/// @brief Is status available?
|
||||
/// Is status available?
|
||||
///
|
||||
/// @param path Input path.
|
||||
/// @param result Set to true if status() != status_error.
|
||||
@@ -421,12 +474,20 @@ enum OpenFlags : unsigned {
|
||||
/// with F_Excl.
|
||||
F_Append = 2,
|
||||
|
||||
/// F_NoTrunc - When opening a file, if it already exists don't truncate
|
||||
/// the file contents. F_Append implies F_NoTrunc, but F_Append seeks to
|
||||
/// the end of the file, which F_NoTrunc doesn't.
|
||||
F_NoTrunc = 4,
|
||||
|
||||
/// The file should be opened in text mode on platforms that make this
|
||||
/// distinction.
|
||||
F_Text = 4,
|
||||
F_Text = 8,
|
||||
|
||||
/// Open the file for read and write.
|
||||
F_RW = 8
|
||||
F_RW = 16,
|
||||
|
||||
/// Delete the file on close. Only makes a difference on windows.
|
||||
F_Delete = 32
|
||||
};
|
||||
|
||||
inline OpenFlags operator|(OpenFlags A, OpenFlags B) {
|
||||
@@ -438,11 +499,41 @@ inline OpenFlags &operator|=(OpenFlags &A, OpenFlags B) {
|
||||
return A;
|
||||
}
|
||||
|
||||
/// @brief Opens the file with the given name in a write-only or read-write
|
||||
/// mode, returning its open file descriptor. If the file does not exist, it
|
||||
/// is created.
|
||||
///
|
||||
/// The caller is responsible for closing the file descriptor once they are
|
||||
/// finished with it.
|
||||
///
|
||||
/// @param Name The path of the file to open, relative or absolute.
|
||||
/// @param ResultFD If the file could be opened successfully, its descriptor
|
||||
/// is stored in this location. Otherwise, this is set to -1.
|
||||
/// @param Flags Additional flags used to determine whether the file should be
|
||||
/// opened in, for example, read-write or in write-only mode.
|
||||
/// @param Mode The access permissions of the file, represented in octal.
|
||||
/// @returns errc::success if \a Name has been opened, otherwise a
|
||||
/// platform-specific error_code.
|
||||
std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
|
||||
OpenFlags Flags, unsigned Mode = 0666);
|
||||
|
||||
/// @brief Opens the file with the given name in a read-only mode, returning
|
||||
/// its open file descriptor.
|
||||
///
|
||||
/// The caller is responsible for closing the file descriptor once they are
|
||||
/// finished with it.
|
||||
///
|
||||
/// @param Name The path of the file to open, relative or absolute.
|
||||
/// @param ResultFD If the file could be opened successfully, its descriptor
|
||||
/// is stored in this location. Otherwise, this is set to -1.
|
||||
/// @param RealPath If nonnull, extra work is done to determine the real path
|
||||
/// of the opened file, and that path is stored in this
|
||||
/// location.
|
||||
/// @returns errc::success if \a Name has been opened, otherwise a
|
||||
/// platform-specific error_code.
|
||||
std::error_code openFileForRead(const Twine &Name, int &ResultFD,
|
||||
SmallVectorImpl<char> *RealPath = nullptr);
|
||||
|
||||
std::error_code getUniqueID(const Twine Path, UniqueID &Result);
|
||||
|
||||
/// @}
|
||||
@@ -454,24 +545,26 @@ std::error_code getUniqueID(const Twine Path, UniqueID &Result);
|
||||
/// called.
|
||||
class directory_entry {
|
||||
std::string Path;
|
||||
mutable file_status Status;
|
||||
bool FollowSymlinks;
|
||||
basic_file_status Status;
|
||||
|
||||
public:
|
||||
explicit directory_entry(const Twine &path, file_status st = file_status())
|
||||
: Path(path.str())
|
||||
, Status(st) {}
|
||||
explicit directory_entry(const Twine &path, bool follow_symlinks = true,
|
||||
basic_file_status st = basic_file_status())
|
||||
: Path(path.str()), FollowSymlinks(follow_symlinks), Status(st) {}
|
||||
|
||||
directory_entry() {}
|
||||
directory_entry() = default;
|
||||
|
||||
void assign(const Twine &path, file_status st = file_status()) {
|
||||
void assign(const Twine &path, basic_file_status st = basic_file_status()) {
|
||||
Path = path.str();
|
||||
Status = st;
|
||||
}
|
||||
|
||||
void replace_filename(const Twine &filename, file_status st = file_status());
|
||||
void replace_filename(const Twine &filename,
|
||||
basic_file_status st = basic_file_status());
|
||||
|
||||
const std::string &path() const { return Path; }
|
||||
std::error_code status(file_status &result) const;
|
||||
ErrorOr<basic_file_status> status() const;
|
||||
|
||||
bool operator==(const directory_entry& rhs) const { return Path == rhs.Path; }
|
||||
bool operator!=(const directory_entry& rhs) const { return !(*this == rhs); }
|
||||
@@ -482,52 +575,59 @@ public:
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct DirIterState;
|
||||
|
||||
std::error_code directory_iterator_construct(DirIterState &, StringRef);
|
||||
std::error_code directory_iterator_construct(DirIterState &, StringRef, bool);
|
||||
std::error_code directory_iterator_increment(DirIterState &);
|
||||
std::error_code directory_iterator_destruct(DirIterState &);
|
||||
|
||||
/// DirIterState - Keeps state for the directory_iterator. It is reference
|
||||
/// counted in order to preserve InputIterator semantics on copy.
|
||||
struct DirIterState : public RefCountedBase<DirIterState> {
|
||||
DirIterState()
|
||||
: IterationHandle(0) {}
|
||||
|
||||
/// Keeps state for the directory_iterator.
|
||||
struct DirIterState {
|
||||
~DirIterState() {
|
||||
directory_iterator_destruct(*this);
|
||||
}
|
||||
|
||||
intptr_t IterationHandle;
|
||||
intptr_t IterationHandle = 0;
|
||||
directory_entry CurrentEntry;
|
||||
};
|
||||
|
||||
} // end namespace detail
|
||||
|
||||
/// directory_iterator - Iterates through the entries in path. There is no
|
||||
/// operator++ because we need an error_code. If it's really needed we can make
|
||||
/// it call report_fatal_error on error.
|
||||
class directory_iterator {
|
||||
IntrusiveRefCntPtr<detail::DirIterState> State;
|
||||
std::shared_ptr<detail::DirIterState> State;
|
||||
bool FollowSymlinks = true;
|
||||
|
||||
public:
|
||||
explicit directory_iterator(const Twine &path, std::error_code &ec) {
|
||||
State = new detail::DirIterState;
|
||||
explicit directory_iterator(const Twine &path, std::error_code &ec,
|
||||
bool follow_symlinks = true)
|
||||
: FollowSymlinks(follow_symlinks) {
|
||||
State = std::make_shared<detail::DirIterState>();
|
||||
SmallString<128> path_storage;
|
||||
ec = detail::directory_iterator_construct(*State,
|
||||
path.toStringRef(path_storage));
|
||||
ec = detail::directory_iterator_construct(
|
||||
*State, path.toStringRef(path_storage), FollowSymlinks);
|
||||
update_error_code_for_current_entry(ec);
|
||||
}
|
||||
|
||||
explicit directory_iterator(const directory_entry &de, std::error_code &ec) {
|
||||
State = new detail::DirIterState;
|
||||
ec = detail::directory_iterator_construct(*State, de.path());
|
||||
explicit directory_iterator(const directory_entry &de, std::error_code &ec,
|
||||
bool follow_symlinks = true)
|
||||
: FollowSymlinks(follow_symlinks) {
|
||||
State = std::make_shared<detail::DirIterState>();
|
||||
ec = detail::directory_iterator_construct(
|
||||
*State, de.path(), FollowSymlinks);
|
||||
update_error_code_for_current_entry(ec);
|
||||
}
|
||||
|
||||
/// Construct end iterator.
|
||||
directory_iterator() : State(nullptr) {}
|
||||
directory_iterator() = default;
|
||||
|
||||
// No operator++ because we need error_code.
|
||||
directory_iterator &increment(std::error_code &ec) {
|
||||
ec = directory_iterator_increment(*State);
|
||||
update_error_code_for_current_entry(ec);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -549,47 +649,64 @@ public:
|
||||
}
|
||||
// Other members as required by
|
||||
// C++ Std, 24.1.1 Input iterators [input.iterators]
|
||||
|
||||
private:
|
||||
// Checks if current entry is valid and populates error code. For example,
|
||||
// current entry may not exist due to broken symbol links.
|
||||
void update_error_code_for_current_entry(std::error_code &ec) {
|
||||
// Bail out if error has already occured earlier to avoid overwriting it.
|
||||
if (ec)
|
||||
return;
|
||||
|
||||
// Empty directory entry is used to mark the end of an interation, it's not
|
||||
// an error.
|
||||
if (State->CurrentEntry == directory_entry())
|
||||
return;
|
||||
|
||||
ErrorOr<basic_file_status> status = State->CurrentEntry.status();
|
||||
if (!status)
|
||||
ec = status.getError();
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
/// RecDirIterState - Keeps state for the recursive_directory_iterator. It is
|
||||
/// reference counted in order to preserve InputIterator semantics on copy.
|
||||
struct RecDirIterState : public RefCountedBase<RecDirIterState> {
|
||||
RecDirIterState()
|
||||
: Level(0)
|
||||
, HasNoPushRequest(false) {}
|
||||
|
||||
std::stack<directory_iterator, std::vector<directory_iterator> > Stack;
|
||||
uint16_t Level;
|
||||
bool HasNoPushRequest;
|
||||
/// Keeps state for the recursive_directory_iterator.
|
||||
struct RecDirIterState {
|
||||
std::stack<directory_iterator, std::vector<directory_iterator>> Stack;
|
||||
uint16_t Level = 0;
|
||||
bool HasNoPushRequest = false;
|
||||
};
|
||||
|
||||
} // end namespace detail
|
||||
|
||||
/// recursive_directory_iterator - Same as directory_iterator except for it
|
||||
/// recurses down into child directories.
|
||||
class recursive_directory_iterator {
|
||||
IntrusiveRefCntPtr<detail::RecDirIterState> State;
|
||||
std::shared_ptr<detail::RecDirIterState> State;
|
||||
bool Follow;
|
||||
|
||||
public:
|
||||
recursive_directory_iterator() {}
|
||||
explicit recursive_directory_iterator(const Twine &path, std::error_code &ec)
|
||||
: State(new detail::RecDirIterState) {
|
||||
State->Stack.push(directory_iterator(path, ec));
|
||||
recursive_directory_iterator() = default;
|
||||
explicit recursive_directory_iterator(const Twine &path, std::error_code &ec,
|
||||
bool follow_symlinks = true)
|
||||
: State(std::make_shared<detail::RecDirIterState>()),
|
||||
Follow(follow_symlinks) {
|
||||
State->Stack.push(directory_iterator(path, ec, Follow));
|
||||
if (State->Stack.top() == directory_iterator())
|
||||
State.reset();
|
||||
}
|
||||
|
||||
// No operator++ because we need error_code.
|
||||
recursive_directory_iterator &increment(std::error_code &ec) {
|
||||
const directory_iterator end_itr;
|
||||
const directory_iterator end_itr = {};
|
||||
|
||||
if (State->HasNoPushRequest)
|
||||
State->HasNoPushRequest = false;
|
||||
else {
|
||||
file_status st;
|
||||
if ((ec = State->Stack.top()->status(st))) return *this;
|
||||
if (is_directory(st)) {
|
||||
State->Stack.push(directory_iterator(*State->Stack.top(), ec));
|
||||
if (ec) return *this;
|
||||
ErrorOr<basic_file_status> status = State->Stack.top()->status();
|
||||
if (status && is_directory(*status)) {
|
||||
State->Stack.push(directory_iterator(*State->Stack.top(), ec, Follow));
|
||||
if (State->Stack.top() != end_itr) {
|
||||
++State->Level;
|
||||
return *this;
|
||||
@@ -627,7 +744,7 @@ public:
|
||||
assert(State && "Cannot pop an end iterator!");
|
||||
assert(State->Level > 0 && "Cannot pop an iterator with level < 1");
|
||||
|
||||
const directory_iterator end_itr;
|
||||
const directory_iterator end_itr = {};
|
||||
std::error_code ec;
|
||||
do {
|
||||
if (ec) {
|
||||
|
||||
@@ -20,9 +20,10 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_FORMAT_H
|
||||
#define LLVM_SUPPORT_FORMAT_H
|
||||
#ifndef WPIUTIL_WPI_FORMAT_H
|
||||
#define WPIUTIL_WPI_FORMAT_H
|
||||
|
||||
#include "wpi/ArrayRef.h"
|
||||
#include "wpi/STLExtras.h"
|
||||
#include "wpi/StringRef.h"
|
||||
#include <cassert>
|
||||
@@ -71,10 +72,20 @@ public:
|
||||
};
|
||||
|
||||
/// These are templated helper classes used by the format function that
|
||||
/// capture the object to be formated and the format string. When actually
|
||||
/// capture the object to be formatted 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.
|
||||
|
||||
// Helper to validate that format() parameters are scalars or pointers.
|
||||
template <typename... Args> struct validate_format_parameters;
|
||||
template <typename Arg, typename... Args>
|
||||
struct validate_format_parameters<Arg, Args...> {
|
||||
static_assert(std::is_scalar<Arg>::value,
|
||||
"format can't be used with non fundamental / non pointer type");
|
||||
validate_format_parameters() { validate_format_parameters<Args...>(); }
|
||||
};
|
||||
template <> struct validate_format_parameters<> {};
|
||||
|
||||
template <typename... Ts>
|
||||
class format_object final : public format_object_base {
|
||||
std::tuple<Ts...> Vals;
|
||||
@@ -98,7 +109,9 @@ class format_object final : public format_object_base {
|
||||
|
||||
public:
|
||||
format_object(const char *fmt, const Ts &... vals)
|
||||
: format_object_base(fmt), Vals(vals...) {}
|
||||
: format_object_base(fmt), Vals(vals...) {
|
||||
validate_format_parameters<Ts...>();
|
||||
}
|
||||
|
||||
int snprint(char *Buffer, unsigned BufferSize) const override {
|
||||
return snprint_tuple(Buffer, BufferSize, index_sequence_for<Ts...>());
|
||||
@@ -119,30 +132,39 @@ 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().
|
||||
/// This is a helper class for left_justify, right_justify, and center_justify.
|
||||
class FormattedString {
|
||||
public:
|
||||
enum Justification { JustifyNone, JustifyLeft, JustifyRight, JustifyCenter };
|
||||
FormattedString(StringRef S, unsigned W, Justification J)
|
||||
: Str(S), Width(W), Justify(J) {}
|
||||
|
||||
private:
|
||||
StringRef Str;
|
||||
unsigned Width;
|
||||
bool RightJustify;
|
||||
Justification Justify;
|
||||
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);
|
||||
return FormattedString(Str, Width, FormattedString::JustifyLeft);
|
||||
}
|
||||
|
||||
/// 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);
|
||||
return FormattedString(Str, Width, FormattedString::JustifyRight);
|
||||
}
|
||||
|
||||
/// center_justify - add spaces before and 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 center_justify(StringRef Str, unsigned Width) {
|
||||
return FormattedString(Str, Width, FormattedString::JustifyCenter);
|
||||
}
|
||||
|
||||
/// This is a helper class used for format_hex() and format_decimal().
|
||||
@@ -197,6 +219,46 @@ inline FormattedNumber format_decimal(int64_t N, unsigned Width) {
|
||||
return FormattedNumber(0, N, Width, false, false, false);
|
||||
}
|
||||
|
||||
class FormattedBytes {
|
||||
ArrayRef<uint8_t> Bytes;
|
||||
|
||||
// If not None, display offsets for each line relative to starting value.
|
||||
Optional<uint64_t> FirstByteOffset;
|
||||
uint32_t IndentLevel; // Number of characters to indent each line.
|
||||
uint32_t NumPerLine; // Number of bytes to show per line.
|
||||
uint8_t ByteGroupSize; // How many hex bytes are grouped without spaces
|
||||
bool Upper; // Show offset and hex bytes as upper case.
|
||||
bool ASCII; // Show the ASCII bytes for the hex bytes to the right.
|
||||
friend class raw_ostream;
|
||||
|
||||
public:
|
||||
FormattedBytes(ArrayRef<uint8_t> B, uint32_t IL, Optional<uint64_t> O,
|
||||
uint32_t NPL, uint8_t BGS, bool U, bool A)
|
||||
: Bytes(B), FirstByteOffset(O), IndentLevel(IL), NumPerLine(NPL),
|
||||
ByteGroupSize(BGS), Upper(U), ASCII(A) {
|
||||
|
||||
if (ByteGroupSize > NumPerLine)
|
||||
ByteGroupSize = NumPerLine;
|
||||
}
|
||||
};
|
||||
|
||||
inline FormattedBytes
|
||||
format_bytes(ArrayRef<uint8_t> Bytes, Optional<uint64_t> FirstByteOffset = None,
|
||||
uint32_t NumPerLine = 16, uint8_t ByteGroupSize = 4,
|
||||
uint32_t IndentLevel = 0, bool Upper = false) {
|
||||
return FormattedBytes(Bytes, IndentLevel, FirstByteOffset, NumPerLine,
|
||||
ByteGroupSize, Upper, false);
|
||||
}
|
||||
|
||||
inline FormattedBytes
|
||||
format_bytes_with_ascii(ArrayRef<uint8_t> Bytes,
|
||||
Optional<uint64_t> FirstByteOffset = None,
|
||||
uint32_t NumPerLine = 16, uint8_t ByteGroupSize = 4,
|
||||
uint32_t IndentLevel = 0, bool Upper = false) {
|
||||
return FormattedBytes(Bytes, IndentLevel, FirstByteOffset, NumPerLine,
|
||||
ByteGroupSize, Upper, true);
|
||||
}
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif
|
||||
|
||||
@@ -42,8 +42,8 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_HASHING_H
|
||||
#define LLVM_ADT_HASHING_H
|
||||
#ifndef WPIUTIL_WPI_HASHING_H
|
||||
#define WPIUTIL_WPI_HASHING_H
|
||||
|
||||
#include "wpi/type_traits.h"
|
||||
#include <algorithm>
|
||||
@@ -55,7 +55,7 @@
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// \brief An opaque object representing a hash code.
|
||||
/// 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.
|
||||
@@ -71,14 +71,14 @@ class hash_code {
|
||||
size_t value;
|
||||
|
||||
public:
|
||||
/// \brief Default construct a hash_code.
|
||||
/// 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.
|
||||
/// 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.
|
||||
/// 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) {
|
||||
@@ -88,11 +88,11 @@ public:
|
||||
return lhs.value != rhs.value;
|
||||
}
|
||||
|
||||
/// \brief Allow a hash_code to be directly run through hash_value.
|
||||
/// 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.
|
||||
/// 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
|
||||
@@ -103,21 +103,21 @@ 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.
|
||||
/// 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.
|
||||
/// 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.
|
||||
/// 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.
|
||||
/// 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
|
||||
@@ -162,7 +162,7 @@ static const uint64_t k1 = 0xb492b66fbe98f273ULL;
|
||||
static const uint64_t k2 = 0x9ae16a3b2f90404fULL;
|
||||
static const uint64_t k3 = 0xc949d7c7509e6557ULL;
|
||||
|
||||
/// \brief Bitwise right rotate.
|
||||
/// 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) {
|
||||
@@ -252,13 +252,13 @@ inline uint64_t hash_short(const char *s, size_t length, uint64_t seed) {
|
||||
return k2 ^ seed;
|
||||
}
|
||||
|
||||
/// \brief The intermediate state used during hashing.
|
||||
/// 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
|
||||
/// 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) {
|
||||
@@ -270,7 +270,7 @@ struct hash_state {
|
||||
return state;
|
||||
}
|
||||
|
||||
/// \brief Mix 32-bytes from the input sequence into the 16-bytes of 'a'
|
||||
/// 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);
|
||||
@@ -282,7 +282,7 @@ struct hash_state {
|
||||
a += c;
|
||||
}
|
||||
|
||||
/// \brief Mix in a 64-byte buffer of data.
|
||||
/// 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) {
|
||||
@@ -300,7 +300,7 @@ struct hash_state {
|
||||
std::swap(h2, h0);
|
||||
}
|
||||
|
||||
/// \brief Compute the final 64-bit hash code value based on the current
|
||||
/// 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,
|
||||
@@ -309,7 +309,7 @@ struct hash_state {
|
||||
};
|
||||
|
||||
|
||||
/// \brief A global, fixed seed-override variable.
|
||||
/// A global, fixed seed-override variable.
|
||||
///
|
||||
/// This variable can be set using the \see wpi::set_fixed_execution_seed
|
||||
/// function. See that function for details. Do not, under any circumstances,
|
||||
@@ -330,7 +330,7 @@ inline size_t get_execution_seed() {
|
||||
}
|
||||
|
||||
|
||||
/// \brief Trait to indicate whether a type's bits can be hashed directly.
|
||||
/// 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
|
||||
@@ -357,14 +357,14 @@ template <typename T, typename U> struct is_hashable_data<std::pair<T, U> >
|
||||
(sizeof(T) + sizeof(U)) ==
|
||||
sizeof(std::pair<T, U>))> {};
|
||||
|
||||
/// \brief Helper to get the hashable data representation for a type.
|
||||
/// 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.
|
||||
/// 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>
|
||||
@@ -374,7 +374,7 @@ get_hashable_data(const T &value) {
|
||||
return hash_value(value);
|
||||
}
|
||||
|
||||
/// \brief Helper to store data from a value into a buffer and advance the
|
||||
/// 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
|
||||
@@ -393,7 +393,7 @@ bool store_and_advance(char *&buffer_ptr, char *buffer_end, const T& value,
|
||||
return true;
|
||||
}
|
||||
|
||||
/// \brief Implement the combining of integral values into a hash_code.
|
||||
/// 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
|
||||
@@ -433,7 +433,7 @@ hash_code hash_combine_range_impl(InputIteratorT first, InputIteratorT last) {
|
||||
return state.finalize(length);
|
||||
}
|
||||
|
||||
/// \brief Implement the combining of integral values into a hash_code.
|
||||
/// 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
|
||||
@@ -468,7 +468,7 @@ hash_combine_range_impl(ValueT *first, ValueT *last) {
|
||||
} // namespace hashing
|
||||
|
||||
|
||||
/// \brief Compute a hash_code for a sequence of values.
|
||||
/// 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
|
||||
@@ -484,7 +484,7 @@ hash_code hash_combine_range(InputIteratorT first, InputIteratorT last) {
|
||||
namespace hashing {
|
||||
namespace detail {
|
||||
|
||||
/// \brief Helper class to manage the recursive combining of hash_combine
|
||||
/// Helper class to manage the recursive combining of hash_combine
|
||||
/// arguments.
|
||||
///
|
||||
/// This class exists to manage the state and various calls involved in the
|
||||
@@ -497,14 +497,14 @@ struct hash_combine_recursive_helper {
|
||||
const size_t seed;
|
||||
|
||||
public:
|
||||
/// \brief Construct a recursive hash combining helper.
|
||||
/// 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.
|
||||
/// 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
|
||||
@@ -545,7 +545,7 @@ public:
|
||||
return buffer_ptr;
|
||||
}
|
||||
|
||||
/// \brief Recursive, variadic combining method.
|
||||
/// Recursive, variadic combining method.
|
||||
///
|
||||
/// This function recurses through each argument, combining that argument
|
||||
/// into a single hash.
|
||||
@@ -558,7 +558,7 @@ public:
|
||||
return combine(length, buffer_ptr, buffer_end, args...);
|
||||
}
|
||||
|
||||
/// \brief Base case for recursive, variadic combining.
|
||||
/// 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
|
||||
@@ -586,7 +586,7 @@ public:
|
||||
} // namespace detail
|
||||
} // namespace hashing
|
||||
|
||||
/// \brief Combine values into a single hash_code.
|
||||
/// 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
|
||||
@@ -608,7 +608,7 @@ template <typename ...Ts> hash_code hash_combine(const Ts &...args) {
|
||||
namespace hashing {
|
||||
namespace detail {
|
||||
|
||||
/// \brief Helper to hash the value of a single integer.
|
||||
/// 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,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//== llvm/ADT/IntrusiveRefCntPtr.h - Smart Refcounting Pointer ---*- C++ -*-==//
|
||||
//==- llvm/ADT/IntrusiveRefCntPtr.h - Smart Refcounting Pointer --*- C++ -*-==//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@@ -7,19 +7,54 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines IntrusiveRefCntPtr, a template class that
|
||||
// implements a "smart" pointer for objects that maintain their own
|
||||
// internal reference count, and RefCountedBase/RefCountedBaseVPTR, two
|
||||
// generic base classes for objects that wish to have their lifetimes
|
||||
// managed using reference counting.
|
||||
// This file defines the RefCountedBase, ThreadSafeRefCountedBase, and
|
||||
// IntrusiveRefCntPtr classes.
|
||||
//
|
||||
// IntrusiveRefCntPtr is similar to Boost's intrusive_ptr with added
|
||||
// LLVM-style casting.
|
||||
// IntrusiveRefCntPtr is a smart pointer to an object which maintains a
|
||||
// reference count. (ThreadSafe)RefCountedBase is a mixin class that adds a
|
||||
// refcount member variable and methods for updating the refcount. An object
|
||||
// that inherits from (ThreadSafe)RefCountedBase deletes itself when its
|
||||
// refcount hits zero.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// class MyClass : public RefCountedBase<MyClass> {};
|
||||
//
|
||||
// void foo() {
|
||||
// // Constructing an IntrusiveRefCntPtr increases the pointee's refcount by
|
||||
// // 1 (from 0 in this case).
|
||||
// IntrusiveRefCntPtr<MyClass> Ptr1(new MyClass());
|
||||
//
|
||||
// // Copying an IntrusiveRefCntPtr increases the pointee's refcount by 1.
|
||||
// IntrusiveRefCntPtr<MyClass> Ptr2(Ptr1);
|
||||
//
|
||||
// // Constructing an IntrusiveRefCntPtr has no effect on the object's
|
||||
// // refcount. After a move, the moved-from pointer is null.
|
||||
// IntrusiveRefCntPtr<MyClass> Ptr3(std::move(Ptr1));
|
||||
// assert(Ptr1 == nullptr);
|
||||
//
|
||||
// // Clearing an IntrusiveRefCntPtr decreases the pointee's refcount by 1.
|
||||
// Ptr2.reset();
|
||||
//
|
||||
// // The object deletes itself when we return from the function, because
|
||||
// // Ptr3's destructor decrements its refcount to 0.
|
||||
// }
|
||||
//
|
||||
// You can use IntrusiveRefCntPtr with isa<T>(), dyn_cast<T>(), etc.:
|
||||
//
|
||||
// IntrusiveRefCntPtr<MyClass> Ptr(new MyClass());
|
||||
// OtherClass *Other = dyn_cast<OtherClass>(Ptr); // Ptr.get() not required
|
||||
//
|
||||
// IntrusiveRefCntPtr works with any class that
|
||||
//
|
||||
// - inherits from (ThreadSafe)RefCountedBase,
|
||||
// - has Retain() and Release() methods, or
|
||||
// - specializes IntrusiveRefCntPtrInfo.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_INTRUSIVEREFCNTPTR_H
|
||||
#define LLVM_ADT_INTRUSIVEREFCNTPTR_H
|
||||
#ifndef WPIUTIL_WPI_INTRUSIVEREFCNTPTR_H
|
||||
#define WPIUTIL_WPI_INTRUSIVEREFCNTPTR_H
|
||||
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
@@ -27,261 +62,208 @@
|
||||
|
||||
namespace wpi {
|
||||
|
||||
template <class T>
|
||||
class IntrusiveRefCntPtr;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// RefCountedBase - A generic base class for objects that wish to
|
||||
/// have their lifetimes managed using reference counts. Classes
|
||||
/// subclass RefCountedBase to obtain such functionality, and are
|
||||
/// typically handled with IntrusiveRefCntPtr "smart pointers" (see below)
|
||||
/// which automatically handle the management of reference counts.
|
||||
/// Objects that subclass RefCountedBase should not be allocated on
|
||||
/// the stack, as invoking "delete" (which is called when the
|
||||
/// reference count hits 0) on such objects is an error.
|
||||
//===----------------------------------------------------------------------===//
|
||||
template <class Derived>
|
||||
class RefCountedBase {
|
||||
mutable unsigned ref_cnt;
|
||||
|
||||
public:
|
||||
RefCountedBase() : ref_cnt(0) {}
|
||||
RefCountedBase(const RefCountedBase &) : ref_cnt(0) {}
|
||||
|
||||
void Retain() const { ++ref_cnt; }
|
||||
void Release() const {
|
||||
assert (ref_cnt > 0 && "Reference count is already zero.");
|
||||
if (--ref_cnt == 0) delete static_cast<const Derived*>(this);
|
||||
}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// RefCountedBaseVPTR - A class that has the same function as
|
||||
/// RefCountedBase, but with a virtual destructor. Should be used
|
||||
/// instead of RefCountedBase for classes that already have virtual
|
||||
/// methods to enforce dynamic allocation via 'new'. Classes that
|
||||
/// inherit from RefCountedBaseVPTR can't be allocated on stack -
|
||||
/// attempting to do this will produce a compile error.
|
||||
//===----------------------------------------------------------------------===//
|
||||
class RefCountedBaseVPTR {
|
||||
mutable unsigned ref_cnt;
|
||||
virtual void anchor();
|
||||
|
||||
protected:
|
||||
RefCountedBaseVPTR() : ref_cnt(0) {}
|
||||
RefCountedBaseVPTR(const RefCountedBaseVPTR &) : ref_cnt(0) {}
|
||||
|
||||
virtual ~RefCountedBaseVPTR() {}
|
||||
|
||||
void Retain() const { ++ref_cnt; }
|
||||
void Release() const {
|
||||
assert (ref_cnt > 0 && "Reference count is already zero.");
|
||||
if (--ref_cnt == 0) delete this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
friend struct IntrusiveRefCntPtrInfo;
|
||||
};
|
||||
|
||||
|
||||
template <typename T> struct IntrusiveRefCntPtrInfo {
|
||||
static void retain(T *obj) { obj->Retain(); }
|
||||
static void release(T *obj) { obj->Release(); }
|
||||
};
|
||||
|
||||
/// \brief A thread-safe version of \c wpi::RefCountedBase.
|
||||
/// A CRTP mixin class that adds reference counting to a type.
|
||||
///
|
||||
/// A generic base class for objects that wish to have their lifetimes managed
|
||||
/// using reference counts. Classes subclass \c ThreadSafeRefCountedBase to
|
||||
/// obtain such functionality, and are typically handled with
|
||||
/// \c IntrusiveRefCntPtr "smart pointers" which automatically handle the
|
||||
/// management of reference counts.
|
||||
template <class Derived>
|
||||
class ThreadSafeRefCountedBase {
|
||||
/// The lifetime of an object which inherits from RefCountedBase is managed by
|
||||
/// calls to Release() and Retain(), which increment and decrement the object's
|
||||
/// refcount, respectively. When a Release() call decrements the refcount to 0,
|
||||
/// the object deletes itself.
|
||||
template <class Derived> class RefCountedBase {
|
||||
mutable unsigned RefCount = 0;
|
||||
|
||||
public:
|
||||
RefCountedBase() = default;
|
||||
RefCountedBase(const RefCountedBase &) {}
|
||||
|
||||
void Retain() const { ++RefCount; }
|
||||
|
||||
void Release() const {
|
||||
assert(RefCount > 0 && "Reference count is already zero.");
|
||||
if (--RefCount == 0)
|
||||
delete static_cast<const Derived *>(this);
|
||||
}
|
||||
};
|
||||
|
||||
/// A thread-safe version of \c RefCountedBase.
|
||||
template <class Derived> class ThreadSafeRefCountedBase {
|
||||
mutable std::atomic<int> RefCount;
|
||||
|
||||
protected:
|
||||
ThreadSafeRefCountedBase() : RefCount(0) {}
|
||||
|
||||
public:
|
||||
void Retain() const { ++RefCount; }
|
||||
void Retain() const { RefCount.fetch_add(1, std::memory_order_relaxed); }
|
||||
|
||||
void Release() const {
|
||||
int NewRefCount = --RefCount;
|
||||
int NewRefCount = RefCount.fetch_sub(1, std::memory_order_acq_rel) - 1;
|
||||
assert(NewRefCount >= 0 && "Reference count was already zero.");
|
||||
if (NewRefCount == 0)
|
||||
delete static_cast<const Derived*>(this);
|
||||
delete static_cast<const Derived *>(this);
|
||||
}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// IntrusiveRefCntPtr - A template class that implements a "smart pointer"
|
||||
/// that assumes the wrapped object has a reference count associated
|
||||
/// with it that can be managed via calls to
|
||||
/// IntrusivePtrAddRef/IntrusivePtrRelease. The smart pointers
|
||||
/// manage reference counts via the RAII idiom: upon creation of
|
||||
/// smart pointer the reference count of the wrapped object is
|
||||
/// incremented and upon destruction of the smart pointer the
|
||||
/// reference count is decremented. This class also safely handles
|
||||
/// wrapping NULL pointers.
|
||||
/// Class you can specialize to provide custom retain/release functionality for
|
||||
/// a type.
|
||||
///
|
||||
/// Reference counting is implemented via calls to
|
||||
/// Obj->Retain()/Obj->Release(). Release() is required to destroy
|
||||
/// the object when the reference count reaches zero. Inheriting from
|
||||
/// RefCountedBase/RefCountedBaseVPTR takes care of this
|
||||
/// automatically.
|
||||
//===----------------------------------------------------------------------===//
|
||||
template <typename T>
|
||||
class IntrusiveRefCntPtr {
|
||||
T* Obj;
|
||||
/// Usually specializing this class is not necessary, as IntrusiveRefCntPtr
|
||||
/// works with any type which defines Retain() and Release() functions -- you
|
||||
/// can define those functions yourself if RefCountedBase doesn't work for you.
|
||||
///
|
||||
/// One case when you might want to specialize this type is if you have
|
||||
/// - Foo.h defines type Foo and includes Bar.h, and
|
||||
/// - Bar.h uses IntrusiveRefCntPtr<Foo> in inline functions.
|
||||
///
|
||||
/// Because Foo.h includes Bar.h, Bar.h can't include Foo.h in order to pull in
|
||||
/// the declaration of Foo. Without the declaration of Foo, normally Bar.h
|
||||
/// wouldn't be able to use IntrusiveRefCntPtr<Foo>, which wants to call
|
||||
/// T::Retain and T::Release.
|
||||
///
|
||||
/// To resolve this, Bar.h could include a third header, FooFwd.h, which
|
||||
/// forward-declares Foo and specializes IntrusiveRefCntPtrInfo<Foo>. Then
|
||||
/// Bar.h could use IntrusiveRefCntPtr<Foo>, although it still couldn't call any
|
||||
/// functions on Foo itself, because Foo would be an incomplete type.
|
||||
template <typename T> struct IntrusiveRefCntPtrInfo {
|
||||
static void retain(T *obj) { obj->Retain(); }
|
||||
static void release(T *obj) { obj->Release(); }
|
||||
};
|
||||
|
||||
public:
|
||||
typedef T element_type;
|
||||
/// A smart pointer to a reference-counted object that inherits from
|
||||
/// RefCountedBase or ThreadSafeRefCountedBase.
|
||||
///
|
||||
/// This class increments its pointee's reference count when it is created, and
|
||||
/// decrements its refcount when it's destroyed (or is changed to point to a
|
||||
/// different object).
|
||||
template <typename T> class IntrusiveRefCntPtr {
|
||||
T *Obj = nullptr;
|
||||
|
||||
explicit IntrusiveRefCntPtr() : Obj(nullptr) {}
|
||||
public:
|
||||
using element_type = T;
|
||||
|
||||
IntrusiveRefCntPtr(T* obj) : Obj(obj) {
|
||||
retain();
|
||||
}
|
||||
explicit IntrusiveRefCntPtr() = default;
|
||||
IntrusiveRefCntPtr(T *obj) : Obj(obj) { retain(); }
|
||||
IntrusiveRefCntPtr(const IntrusiveRefCntPtr &S) : Obj(S.Obj) { retain(); }
|
||||
IntrusiveRefCntPtr(IntrusiveRefCntPtr &&S) : Obj(S.Obj) { S.Obj = nullptr; }
|
||||
|
||||
IntrusiveRefCntPtr(const IntrusiveRefCntPtr& S) : Obj(S.Obj) {
|
||||
retain();
|
||||
}
|
||||
|
||||
IntrusiveRefCntPtr(IntrusiveRefCntPtr&& S) : Obj(S.Obj) {
|
||||
S.Obj = nullptr;
|
||||
}
|
||||
|
||||
template <class X>
|
||||
IntrusiveRefCntPtr(IntrusiveRefCntPtr<X>&& S) : Obj(S.get()) {
|
||||
S.Obj = nullptr;
|
||||
}
|
||||
|
||||
template <class X>
|
||||
IntrusiveRefCntPtr(const IntrusiveRefCntPtr<X>& S)
|
||||
: Obj(S.get()) {
|
||||
retain();
|
||||
}
|
||||
|
||||
IntrusiveRefCntPtr& operator=(IntrusiveRefCntPtr S) {
|
||||
swap(S);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~IntrusiveRefCntPtr() { release(); }
|
||||
|
||||
T& operator*() const { return *Obj; }
|
||||
|
||||
T* operator->() const { return Obj; }
|
||||
|
||||
T* get() const { return Obj; }
|
||||
|
||||
explicit operator bool() const { return Obj; }
|
||||
|
||||
void swap(IntrusiveRefCntPtr& other) {
|
||||
T* tmp = other.Obj;
|
||||
other.Obj = Obj;
|
||||
Obj = tmp;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
release();
|
||||
Obj = nullptr;
|
||||
}
|
||||
|
||||
void resetWithoutRelease() {
|
||||
Obj = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
void retain() { if (Obj) IntrusiveRefCntPtrInfo<T>::retain(Obj); }
|
||||
void release() { if (Obj) IntrusiveRefCntPtrInfo<T>::release(Obj); }
|
||||
|
||||
template <typename X>
|
||||
friend class IntrusiveRefCntPtr;
|
||||
};
|
||||
|
||||
template<class T, class U>
|
||||
inline bool operator==(const IntrusiveRefCntPtr<T>& A,
|
||||
const IntrusiveRefCntPtr<U>& B)
|
||||
{
|
||||
return A.get() == B.get();
|
||||
template <class X>
|
||||
IntrusiveRefCntPtr(IntrusiveRefCntPtr<X> &&S) : Obj(S.get()) {
|
||||
S.Obj = nullptr;
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline bool operator!=(const IntrusiveRefCntPtr<T>& A,
|
||||
const IntrusiveRefCntPtr<U>& B)
|
||||
{
|
||||
return A.get() != B.get();
|
||||
template <class X>
|
||||
IntrusiveRefCntPtr(const IntrusiveRefCntPtr<X> &S) : Obj(S.get()) {
|
||||
retain();
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline bool operator==(const IntrusiveRefCntPtr<T>& A,
|
||||
U* B)
|
||||
{
|
||||
return A.get() == B;
|
||||
~IntrusiveRefCntPtr() { release(); }
|
||||
|
||||
IntrusiveRefCntPtr &operator=(IntrusiveRefCntPtr S) {
|
||||
swap(S);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline bool operator!=(const IntrusiveRefCntPtr<T>& A,
|
||||
U* B)
|
||||
{
|
||||
return A.get() != B;
|
||||
T &operator*() const { return *Obj; }
|
||||
T *operator->() const { return Obj; }
|
||||
T *get() const { return Obj; }
|
||||
explicit operator bool() const { return Obj; }
|
||||
|
||||
void swap(IntrusiveRefCntPtr &other) {
|
||||
T *tmp = other.Obj;
|
||||
other.Obj = Obj;
|
||||
Obj = tmp;
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline bool operator==(T* A,
|
||||
const IntrusiveRefCntPtr<U>& B)
|
||||
{
|
||||
return A == B.get();
|
||||
void reset() {
|
||||
release();
|
||||
Obj = nullptr;
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline bool operator!=(T* A,
|
||||
const IntrusiveRefCntPtr<U>& B)
|
||||
{
|
||||
return A != B.get();
|
||||
void resetWithoutRelease() { Obj = nullptr; }
|
||||
|
||||
private:
|
||||
void retain() {
|
||||
if (Obj)
|
||||
IntrusiveRefCntPtrInfo<T>::retain(Obj);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool operator==(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) {
|
||||
return !B;
|
||||
void release() {
|
||||
if (Obj)
|
||||
IntrusiveRefCntPtrInfo<T>::release(Obj);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool operator==(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) {
|
||||
return B == A;
|
||||
template <typename X> friend class IntrusiveRefCntPtr;
|
||||
};
|
||||
|
||||
template <class T, class U>
|
||||
inline bool operator==(const IntrusiveRefCntPtr<T> &A,
|
||||
const IntrusiveRefCntPtr<U> &B) {
|
||||
return A.get() == B.get();
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
inline bool operator!=(const IntrusiveRefCntPtr<T> &A,
|
||||
const IntrusiveRefCntPtr<U> &B) {
|
||||
return A.get() != B.get();
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
inline bool operator==(const IntrusiveRefCntPtr<T> &A, U *B) {
|
||||
return A.get() == B;
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
inline bool operator!=(const IntrusiveRefCntPtr<T> &A, U *B) {
|
||||
return A.get() != B;
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
inline bool operator==(T *A, const IntrusiveRefCntPtr<U> &B) {
|
||||
return A == B.get();
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
inline bool operator!=(T *A, const IntrusiveRefCntPtr<U> &B) {
|
||||
return A != B.get();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool operator==(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) {
|
||||
return !B;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool operator==(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) {
|
||||
return B == A;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool operator!=(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) {
|
||||
return !(A == B);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool operator!=(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) {
|
||||
return !(A == B);
|
||||
}
|
||||
|
||||
// Make IntrusiveRefCntPtr work with dyn_cast, isa, and the other idioms from
|
||||
// Casting.h.
|
||||
template <typename From> struct simplify_type;
|
||||
|
||||
template <class T> struct simplify_type<IntrusiveRefCntPtr<T>> {
|
||||
using SimpleType = T *;
|
||||
|
||||
static SimpleType getSimplifiedValue(IntrusiveRefCntPtr<T> &Val) {
|
||||
return Val.get();
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
bool operator!=(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) {
|
||||
return !(A == B);
|
||||
template <class T> struct simplify_type<const IntrusiveRefCntPtr<T>> {
|
||||
using SimpleType = /*const*/ T *;
|
||||
|
||||
static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T> &Val) {
|
||||
return Val.get();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool operator!=(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) {
|
||||
return !(A == B);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// LLVM-style downcasting support for IntrusiveRefCntPtr objects
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
template <typename From> struct simplify_type;
|
||||
|
||||
template<class T> struct simplify_type<IntrusiveRefCntPtr<T> > {
|
||||
typedef T* SimpleType;
|
||||
static SimpleType getSimplifiedValue(IntrusiveRefCntPtr<T>& Val) {
|
||||
return Val.get();
|
||||
}
|
||||
};
|
||||
|
||||
template<class T> struct simplify_type<const IntrusiveRefCntPtr<T> > {
|
||||
typedef /*const*/ T* SimpleType;
|
||||
static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T>& Val) {
|
||||
return Val.get();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
|
||||
@@ -11,33 +11,108 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_MATHEXTRAS_H
|
||||
#define LLVM_SUPPORT_MATHEXTRAS_H
|
||||
#ifndef WPIUTIL_WPI_MATHEXTRAS_H
|
||||
#define WPIUTIL_WPI_MATHEXTRAS_H
|
||||
|
||||
#include "wpi/Compiler.h"
|
||||
#include <cstdint>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <type_traits>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
namespace wpi {
|
||||
/// \brief The behavior an operation has on an input of 0.
|
||||
/// The behavior an operation has on an input of 0.
|
||||
enum ZeroBehavior {
|
||||
/// \brief The returned value is undefined.
|
||||
/// The returned value is undefined.
|
||||
ZB_Undefined,
|
||||
/// \brief The returned value is numeric_limits<T>::max()
|
||||
/// The returned value is numeric_limits<T>::max()
|
||||
ZB_Max,
|
||||
/// \brief The returned value is numeric_limits<T>::digits
|
||||
/// The returned value is numeric_limits<T>::digits
|
||||
ZB_Width
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
template <typename T, std::size_t SizeOfT> struct TrailingZerosCounter {
|
||||
static std::size_t count(T Val, ZeroBehavior) {
|
||||
if (!Val)
|
||||
return std::numeric_limits<T>::digits;
|
||||
if (Val & 0x1)
|
||||
return 0;
|
||||
|
||||
// Bisection method.
|
||||
std::size_t ZeroBits = 0;
|
||||
T Shift = std::numeric_limits<T>::digits >> 1;
|
||||
T Mask = std::numeric_limits<T>::max() >> Shift;
|
||||
while (Shift) {
|
||||
if ((Val & Mask) == 0) {
|
||||
Val >>= Shift;
|
||||
ZeroBits |= Shift;
|
||||
}
|
||||
Shift >>= 1;
|
||||
Mask >>= Shift;
|
||||
}
|
||||
return ZeroBits;
|
||||
}
|
||||
};
|
||||
|
||||
#if __GNUC__ >= 4 || defined(_MSC_VER)
|
||||
template <typename T> struct TrailingZerosCounter<T, 4> {
|
||||
static std::size_t count(T Val, ZeroBehavior ZB) {
|
||||
if (ZB != ZB_Undefined && Val == 0)
|
||||
return 32;
|
||||
|
||||
#if __has_builtin(__builtin_ctz) || LLVM_GNUC_PREREQ(4, 0, 0)
|
||||
return __builtin_ctz(Val);
|
||||
#elif defined(_MSC_VER)
|
||||
unsigned long Index;
|
||||
_BitScanForward(&Index, Val);
|
||||
return Index;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#if !defined(_MSC_VER) || defined(_M_X64)
|
||||
template <typename T> struct TrailingZerosCounter<T, 8> {
|
||||
static std::size_t count(T Val, ZeroBehavior ZB) {
|
||||
if (ZB != ZB_Undefined && Val == 0)
|
||||
return 64;
|
||||
|
||||
#if __has_builtin(__builtin_ctzll) || LLVM_GNUC_PREREQ(4, 0, 0)
|
||||
return __builtin_ctzll(Val);
|
||||
#elif defined(_MSC_VER)
|
||||
unsigned long Index;
|
||||
_BitScanForward64(&Index, Val);
|
||||
return Index;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
} // namespace detail
|
||||
|
||||
/// Count number of 0's from the least significant bit to the most
|
||||
/// 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 countTrailingZeros(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 wpi::detail::TrailingZerosCounter<T, sizeof(T)>::count(Val, ZB);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template <typename T, std::size_t SizeOfT> struct LeadingZerosCounter {
|
||||
static std::size_t count(T Val, ZeroBehavior) {
|
||||
@@ -92,7 +167,7 @@ template <typename T> struct LeadingZerosCounter<T, 8> {
|
||||
#endif
|
||||
} // namespace detail
|
||||
|
||||
/// \brief Count number of 0's from the most significant bit to the least
|
||||
/// Count number of 0's from the most significant bit to the least
|
||||
/// stopping at the first 1.
|
||||
///
|
||||
/// Only unsigned integral types are allowed.
|
||||
@@ -104,10 +179,51 @@ 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);
|
||||
return wpi::detail::LeadingZerosCounter<T, sizeof(T)>::count(Val, ZB);
|
||||
}
|
||||
|
||||
/// \brief Get the index of the last set bit starting from the least
|
||||
/// Get the index of the first 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 findFirstSet(T Val, ZeroBehavior ZB = ZB_Max) {
|
||||
if (ZB == ZB_Max && Val == 0)
|
||||
return std::numeric_limits<T>::max();
|
||||
|
||||
return countTrailingZeros(Val, ZB_Undefined);
|
||||
}
|
||||
|
||||
/// Create a bitmask with the N right-most bits set to 1, and all other
|
||||
/// bits set to 0. Only unsigned types are allowed.
|
||||
template <typename T> T maskTrailingOnes(unsigned N) {
|
||||
static_assert(std::is_unsigned<T>::value, "Invalid type!");
|
||||
const unsigned Bits = CHAR_BIT * sizeof(T);
|
||||
assert(N <= Bits && "Invalid bit index");
|
||||
return N == 0 ? 0 : (T(-1) >> (Bits - N));
|
||||
}
|
||||
|
||||
/// Create a bitmask with the N left-most bits set to 1, and all other
|
||||
/// bits set to 0. Only unsigned types are allowed.
|
||||
template <typename T> T maskLeadingOnes(unsigned N) {
|
||||
return ~maskTrailingOnes<T>(CHAR_BIT * sizeof(T) - N);
|
||||
}
|
||||
|
||||
/// Create a bitmask with the N right-most bits set to 0, and all other
|
||||
/// bits set to 1. Only unsigned types are allowed.
|
||||
template <typename T> T maskTrailingZeros(unsigned N) {
|
||||
return maskLeadingOnes<T>(CHAR_BIT * sizeof(T) - N);
|
||||
}
|
||||
|
||||
/// Create a bitmask with the N left-most bits set to 0, and all other
|
||||
/// bits set to 1. Only unsigned types are allowed.
|
||||
template <typename T> T maskLeadingZeros(unsigned N) {
|
||||
return maskTrailingOnes<T>(CHAR_BIT * sizeof(T) - N);
|
||||
}
|
||||
|
||||
/// Get the index of the last set bit starting from the least
|
||||
/// significant bit.
|
||||
///
|
||||
/// Only unsigned integral types are allowed.
|
||||
@@ -124,7 +240,7 @@ template <typename T> T findLastSet(T Val, ZeroBehavior ZB = ZB_Max) {
|
||||
(std::numeric_limits<T>::digits - 1);
|
||||
}
|
||||
|
||||
/// \brief Macro compressed bit reversal table for 256 bits.
|
||||
/// Macro compressed bit reversal table for 256 bits.
|
||||
///
|
||||
/// http://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable
|
||||
static const unsigned char BitReverseTable256[256] = {
|
||||
@@ -137,7 +253,7 @@ static const unsigned char BitReverseTable256[256] = {
|
||||
#undef R6
|
||||
};
|
||||
|
||||
/// \brief Reverse the bits in \p Val.
|
||||
/// Reverse the bits in \p Val.
|
||||
template <typename T>
|
||||
T reverseBits(T Val) {
|
||||
unsigned char in[sizeof(Val)];
|
||||
@@ -153,150 +269,165 @@ T reverseBits(T Val) {
|
||||
// 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 the high 32 bits of a 64 bit value.
|
||||
constexpr 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 the low 32 bits of a 64 bit value.
|
||||
constexpr 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) {
|
||||
/// Make a 64-bit integer from a high / low pair of 32-bit integers.
|
||||
constexpr 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) {
|
||||
/// Checks if an integer fits into the given bit width.
|
||||
template <unsigned N> constexpr 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) {
|
||||
template <> constexpr inline bool isInt<8>(int64_t x) {
|
||||
return static_cast<int8_t>(x) == x;
|
||||
}
|
||||
template<>
|
||||
inline bool isInt<16>(int64_t x) {
|
||||
template <> constexpr inline bool isInt<16>(int64_t x) {
|
||||
return static_cast<int16_t>(x) == x;
|
||||
}
|
||||
template<>
|
||||
inline bool isInt<32>(int64_t x) {
|
||||
template <> constexpr 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);
|
||||
/// Checks if a signed integer is an N bit number shifted left by S.
|
||||
template <unsigned N, unsigned S>
|
||||
constexpr inline bool isShiftedInt(int64_t x) {
|
||||
static_assert(
|
||||
N > 0, "isShiftedInt<0> doesn't make sense (refers to a 0-bit number.");
|
||||
static_assert(N + S <= 64, "isShiftedInt<N, S> with N + S > 64 is too wide.");
|
||||
return isInt<N + S>(x) && (x % (UINT64_C(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));
|
||||
/// Checks if an unsigned integer fits into the given bit width.
|
||||
///
|
||||
/// This is written as two functions rather than as simply
|
||||
///
|
||||
/// return N >= 64 || X < (UINT64_C(1) << N);
|
||||
///
|
||||
/// to keep MSVC from (incorrectly) warning on isUInt<64> that we're shifting
|
||||
/// left too many places.
|
||||
template <unsigned N>
|
||||
constexpr inline typename std::enable_if<(N < 64), bool>::type
|
||||
isUInt(uint64_t X) {
|
||||
static_assert(N > 0, "isUInt<0> doesn't make sense");
|
||||
return X < (UINT64_C(1) << (N));
|
||||
}
|
||||
template <unsigned N>
|
||||
constexpr inline typename std::enable_if<N >= 64, bool>::type
|
||||
isUInt(uint64_t X) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Template specializations to get better code for common cases.
|
||||
template<>
|
||||
inline bool isUInt<8>(uint64_t x) {
|
||||
template <> constexpr inline bool isUInt<8>(uint64_t x) {
|
||||
return static_cast<uint8_t>(x) == x;
|
||||
}
|
||||
template<>
|
||||
inline bool isUInt<16>(uint64_t x) {
|
||||
template <> constexpr inline bool isUInt<16>(uint64_t x) {
|
||||
return static_cast<uint16_t>(x) == x;
|
||||
}
|
||||
template<>
|
||||
inline bool isUInt<32>(uint64_t x) {
|
||||
template <> constexpr 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);
|
||||
/// Checks if a unsigned integer is an N bit number shifted left by S.
|
||||
template <unsigned N, unsigned S>
|
||||
constexpr inline bool isShiftedUInt(uint64_t x) {
|
||||
static_assert(
|
||||
N > 0, "isShiftedUInt<0> doesn't make sense (refers to a 0-bit number)");
|
||||
static_assert(N + S <= 64,
|
||||
"isShiftedUInt<N, S> with N + S > 64 is too wide.");
|
||||
// Per the two static_asserts above, S must be strictly less than 64. So
|
||||
// 1 << S is not undefined behavior.
|
||||
return isUInt<N + S>(x) && (x % (UINT64_C(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;
|
||||
// uint64_t(1) << 64 is undefined behavior, so we can't do
|
||||
// (uint64_t(1) << N) - 1
|
||||
// without checking first that N != 64. But this works and doesn't have a
|
||||
// branch.
|
||||
return UINT64_MAX >> (64 - N);
|
||||
}
|
||||
|
||||
/// 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));
|
||||
return -(UINT64_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;
|
||||
// This relies on two's complement wraparound when N == 64, so we convert to
|
||||
// int64_t only at the very end to avoid UB.
|
||||
return (UINT64_C(1) << (N - 1)) - 1;
|
||||
}
|
||||
|
||||
/// isUIntN - Checks if an unsigned integer fits into the given (dynamic)
|
||||
/// bit width.
|
||||
/// 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.
|
||||
/// 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 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.
|
||||
constexpr 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 true if the argument is a non-empty sequence of ones starting at the
|
||||
/// least significant bit with the remainder zero (64 bit version).
|
||||
constexpr 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 true if the argument contains a non-empty sequence of ones with the
|
||||
/// remainder zero (32 bit version.) Ex. isShiftedMask_32(0x0000FF00U) == true.
|
||||
constexpr 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 true if the argument contains a non-empty sequence of ones with the
|
||||
/// remainder zero (64 bit version.)
|
||||
constexpr 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 true if the argument is a power of two > 0.
|
||||
/// Ex. isPowerOf2_32(0x00100000U) == true (32 bit edition.)
|
||||
constexpr 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)));
|
||||
/// Return true if the argument is a power of two > 0 (64 bit edition.)
|
||||
constexpr inline bool isPowerOf2_64(uint64_t Value) {
|
||||
return Value && !(Value & (Value - 1));
|
||||
}
|
||||
|
||||
/// \brief Count the number of ones from the most significant bit to the first
|
||||
/// Count the number of ones from the most significant bit to the first
|
||||
/// zero bit.
|
||||
///
|
||||
/// Ex. CountLeadingOnes(0xFF0FFF00) == 8.
|
||||
/// Ex. countLeadingOnes(0xFF0FFF00) == 8.
|
||||
/// Only unsigned integral types are allowed.
|
||||
///
|
||||
/// \param ZB the behavior on an input of all ones. Only ZB_Width and
|
||||
@@ -306,7 +437,23 @@ 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);
|
||||
return countLeadingZeros<T>(~Value, ZB);
|
||||
}
|
||||
|
||||
/// Count the number of ones from the least significant bit to the first
|
||||
/// zero bit.
|
||||
///
|
||||
/// Ex. countTrailingOnes(0x00FF00FF) == 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 countTrailingOnes(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 countTrailingZeros<T>(~Value, ZB);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
@@ -340,7 +487,7 @@ template <typename T> struct PopulationCounter<T, 8> {
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
/// \brief Count the number of set bits in a value.
|
||||
/// Count the number of set bits in a value.
|
||||
/// Ex. countPopulation(0xF000F000) = 8
|
||||
/// Returns 0 if the word is zero.
|
||||
template <typename T>
|
||||
@@ -351,7 +498,7 @@ inline unsigned countPopulation(T Value) {
|
||||
return detail::PopulationCounter<T, sizeof(T)>::count(Value);
|
||||
}
|
||||
|
||||
/// Log2 - This function returns the log base 2 of the specified value
|
||||
/// Return 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);
|
||||
@@ -360,34 +507,33 @@ inline double Log2(double 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.)
|
||||
/// Return 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.)
|
||||
/// Return 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).
|
||||
/// Return 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.)
|
||||
/// Return 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.
|
||||
/// Return the greatest common divisor of the values using Euclid's algorithm.
|
||||
inline uint64_t GreatestCommonDivisor64(uint64_t A, uint64_t B) {
|
||||
while (B) {
|
||||
uint64_t T = B;
|
||||
@@ -397,57 +543,45 @@ inline uint64_t GreatestCommonDivisor64(uint64_t A, uint64_t B) {
|
||||
return A;
|
||||
}
|
||||
|
||||
/// BitsToDouble - This function takes a 64-bit integer and returns the bit
|
||||
/// equivalent double.
|
||||
/// 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;
|
||||
double D;
|
||||
static_assert(sizeof(uint64_t) == sizeof(double), "Unexpected type sizes");
|
||||
memcpy(&D, &Bits, sizeof(Bits));
|
||||
return D;
|
||||
}
|
||||
|
||||
/// BitsToFloat - This function takes a 32-bit integer and returns the bit
|
||||
/// equivalent float.
|
||||
/// 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;
|
||||
float F;
|
||||
static_assert(sizeof(uint32_t) == sizeof(float), "Unexpected type sizes");
|
||||
memcpy(&F, &Bits, sizeof(Bits));
|
||||
return 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.
|
||||
/// 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;
|
||||
uint64_t Bits;
|
||||
static_assert(sizeof(uint64_t) == sizeof(double), "Unexpected type sizes");
|
||||
memcpy(&Bits, &Double, sizeof(Double));
|
||||
return Bits;
|
||||
}
|
||||
|
||||
/// 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.
|
||||
/// 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;
|
||||
uint32_t Bits;
|
||||
static_assert(sizeof(uint32_t) == sizeof(float), "Unexpected type sizes");
|
||||
memcpy(&Bits, &Float, sizeof(Float));
|
||||
return Bits;
|
||||
}
|
||||
|
||||
/// 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) {
|
||||
/// A and B are either alignments or offsets. Return the minimum alignment that
|
||||
/// may be assumed after adding the two together.
|
||||
constexpr 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
|
||||
@@ -456,7 +590,7 @@ inline uint64_t MinAlign(uint64_t A, uint64_t B) {
|
||||
return (A | B) & (1 + ~(A | B));
|
||||
}
|
||||
|
||||
/// \brief Aligns \c Addr to \c Alignment bytes, rounding up.
|
||||
/// 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.
|
||||
@@ -469,14 +603,14 @@ inline uintptr_t alignAddr(const void *Addr, size_t Alignment) {
|
||||
return (((uintptr_t)Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1));
|
||||
}
|
||||
|
||||
/// \brief Returns the necessary adjustment for aligning \c Ptr to \c Alignment
|
||||
/// 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.
|
||||
/// 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);
|
||||
@@ -494,6 +628,14 @@ inline uint64_t PowerOf2Floor(uint64_t A) {
|
||||
return 1ull << (63 - countLeadingZeros(A, ZB_Undefined));
|
||||
}
|
||||
|
||||
/// Returns the power of two which is greater than or equal to the given value.
|
||||
/// Essentially, it is a ceil operation across the domain of powers of two.
|
||||
inline uint64_t PowerOf2Ceil(uint64_t A) {
|
||||
if (!A)
|
||||
return 0;
|
||||
return NextPowerOf2(A - 1);
|
||||
}
|
||||
|
||||
/// 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.
|
||||
///
|
||||
@@ -515,13 +657,40 @@ inline uint64_t PowerOf2Floor(uint64_t A) {
|
||||
/// alignTo(321, 255, 42) = 552
|
||||
/// \endcode
|
||||
inline uint64_t alignTo(uint64_t Value, uint64_t Align, uint64_t Skew = 0) {
|
||||
assert(Align != 0u && "Align can't be 0.");
|
||||
Skew %= Align;
|
||||
return (Value + Align - 1 - Skew) / Align * Align + Skew;
|
||||
}
|
||||
|
||||
/// Returns the next integer (mod 2**64) that is greater than or equal to
|
||||
/// \p Value and is a multiple of \c Align. \c Align must be non-zero.
|
||||
template <uint64_t Align> constexpr inline uint64_t alignTo(uint64_t Value) {
|
||||
static_assert(Align != 0u, "Align must be non-zero");
|
||||
return (Value + Align - 1) / Align * Align;
|
||||
}
|
||||
|
||||
/// Returns the integer ceil(Numerator / Denominator).
|
||||
inline uint64_t divideCeil(uint64_t Numerator, uint64_t Denominator) {
|
||||
return alignTo(Numerator, Denominator) / Denominator;
|
||||
}
|
||||
|
||||
/// \c alignTo for contexts where a constant expression is required.
|
||||
/// \sa alignTo
|
||||
///
|
||||
/// \todo FIXME: remove when \c constexpr becomes really \c constexpr
|
||||
template <uint64_t Align>
|
||||
struct AlignTo {
|
||||
static_assert(Align != 0u, "Align must be non-zero");
|
||||
template <uint64_t Value>
|
||||
struct from_value {
|
||||
static const uint64_t value = (Value + Align - 1) / Align * Align;
|
||||
};
|
||||
};
|
||||
|
||||
/// 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) {
|
||||
assert(Align != 0u && "Align can't be 0.");
|
||||
Skew %= Align;
|
||||
return (Value - Skew) / Align * Align + Skew;
|
||||
}
|
||||
@@ -533,42 +702,49 @@ 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.
|
||||
/// Sign-extend the number in the bottom B bits of X to a 32-bit integer.
|
||||
/// Requires 0 < B <= 32.
|
||||
inline int32_t SignExtend32(uint32_t X, unsigned B) {
|
||||
template <unsigned B> constexpr inline int32_t SignExtend32(uint32_t X) {
|
||||
static_assert(B > 0, "Bit width can't be 0.");
|
||||
static_assert(B <= 32, "Bit width out of range.");
|
||||
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) {
|
||||
/// Sign-extend the number in the bottom B bits of X to a 32-bit integer.
|
||||
/// Requires 0 < B < 32.
|
||||
inline int32_t SignExtend32(uint32_t X, unsigned B) {
|
||||
assert(B > 0 && "Bit width can't be 0.");
|
||||
assert(B <= 32 && "Bit width out of range.");
|
||||
return int32_t(X << (32 - B)) >> (32 - B);
|
||||
}
|
||||
|
||||
/// Sign-extend the number in the bottom B bits of X to a 64-bit integer.
|
||||
/// Requires 0 < B < 64.
|
||||
template <unsigned B> constexpr inline int64_t SignExtend64(uint64_t x) {
|
||||
static_assert(B > 0, "Bit width can't be 0.");
|
||||
static_assert(B <= 64, "Bit width out of range.");
|
||||
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.
|
||||
/// Sign-extend the number in the bottom B bits of X to a 64-bit integer.
|
||||
/// Requires 0 < B < 64.
|
||||
inline int64_t SignExtend64(uint64_t X, unsigned B) {
|
||||
assert(B > 0 && "Bit width can't be 0.");
|
||||
assert(B <= 64 && "Bit width out of range.");
|
||||
return int64_t(X << (64 - B)) >> (64 - B);
|
||||
}
|
||||
|
||||
/// \brief Subtract two unsigned integers, X and Y, of type T and return their
|
||||
/// absolute value.
|
||||
/// Subtract two unsigned integers, X and Y, of type T and return the absolute
|
||||
/// value of the result.
|
||||
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.
|
||||
/// 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) {
|
||||
@@ -583,10 +759,9 @@ SaturatingAdd(T X, T Y, bool *ResultOverflowed = nullptr) {
|
||||
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.
|
||||
/// 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) {
|
||||
@@ -629,12 +804,10 @@ SaturatingMultiply(T X, T Y, bool *ResultOverflowed = nullptr) {
|
||||
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.
|
||||
/// 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.
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_unsigned<T>::value, T>::type
|
||||
SaturatingMultiplyAdd(T X, T Y, T A, bool *ResultOverflowed = nullptr) {
|
||||
|
||||
49
wpiutil/src/main/native/include/wpi/NativeFormatting.h
Normal file
49
wpiutil/src/main/native/include/wpi/NativeFormatting.h
Normal file
@@ -0,0 +1,49 @@
|
||||
//===- NativeFormatting.h - Low level formatting helpers ---------*- C++-*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_NATIVE_FORMATTING_H
|
||||
#define WPIUTIL_WPI_NATIVE_FORMATTING_H
|
||||
|
||||
#include "wpi/Optional.h"
|
||||
#include "wpi/raw_ostream.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace wpi {
|
||||
enum class FloatStyle { Exponent, ExponentUpper, Fixed, Percent };
|
||||
enum class IntegerStyle {
|
||||
Integer,
|
||||
Number,
|
||||
};
|
||||
enum class HexPrintStyle { Upper, Lower, PrefixUpper, PrefixLower };
|
||||
|
||||
size_t getDefaultPrecision(FloatStyle Style);
|
||||
|
||||
bool isPrefixedHexStyle(HexPrintStyle S);
|
||||
|
||||
void write_integer(raw_ostream &S, unsigned int N, size_t MinDigits,
|
||||
IntegerStyle Style);
|
||||
void write_integer(raw_ostream &S, int N, size_t MinDigits, IntegerStyle Style);
|
||||
void write_integer(raw_ostream &S, unsigned long N, size_t MinDigits,
|
||||
IntegerStyle Style);
|
||||
void write_integer(raw_ostream &S, long N, size_t MinDigits,
|
||||
IntegerStyle Style);
|
||||
void write_integer(raw_ostream &S, unsigned long long N, size_t MinDigits,
|
||||
IntegerStyle Style);
|
||||
void write_integer(raw_ostream &S, long long N, size_t MinDigits,
|
||||
IntegerStyle Style);
|
||||
|
||||
void write_hex(raw_ostream &S, uint64_t N, HexPrintStyle Style,
|
||||
Optional<size_t> Width = None);
|
||||
void write_double(raw_ostream &S, double D, FloatStyle Style,
|
||||
Optional<size_t> Precision = None);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -13,14 +13,15 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_NONE_H
|
||||
#define LLVM_ADT_NONE_H
|
||||
#ifndef WPIUTIL_WPI_NONE_H
|
||||
#define WPIUTIL_WPI_NONE_H
|
||||
|
||||
namespace wpi {
|
||||
/// \brief A simple null object to allow implicit construction of Optional<T>
|
||||
/// 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;
|
||||
// (constant value 1 in an attempt to workaround MSVC build issue... )
|
||||
enum class NoneType { None = 1 };
|
||||
const NoneType None = NoneType::None;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//===-- Optional.h - Simple variant for passing optional values ---*- C++ -*-=//
|
||||
//===- Optional.h - Simple variant for passing optional values --*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@@ -13,129 +13,187 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_OPTIONAL_H
|
||||
#define LLVM_ADT_OPTIONAL_H
|
||||
#ifndef WPIUTIL_WPI_OPTIONAL_H
|
||||
#define WPIUTIL_WPI_OPTIONAL_H
|
||||
|
||||
#include "wpi/None.h"
|
||||
#include "wpi/AlignOf.h"
|
||||
#include "wpi/Compiler.h"
|
||||
#include "wpi/type_traits.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <new>
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
template<typename T>
|
||||
class Optional {
|
||||
namespace optional_detail {
|
||||
/// Storage for any type.
|
||||
template <typename T, bool IsPodLike> struct OptionalStorage {
|
||||
AlignedCharArrayUnion<T> storage;
|
||||
bool hasVal;
|
||||
public:
|
||||
typedef T value_type;
|
||||
bool hasVal = false;
|
||||
|
||||
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) {
|
||||
OptionalStorage() = default;
|
||||
|
||||
OptionalStorage(const T &y) : hasVal(true) { new (storage.buffer) T(y); }
|
||||
OptionalStorage(const OptionalStorage &O) : hasVal(O.hasVal) {
|
||||
if (hasVal)
|
||||
new (storage.buffer) T(*O);
|
||||
new (storage.buffer) T(*O.getPointer());
|
||||
}
|
||||
|
||||
Optional(T &&y) : hasVal(true) {
|
||||
OptionalStorage(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();
|
||||
OptionalStorage(OptionalStorage &&O) : hasVal(O.hasVal) {
|
||||
if (O.hasVal) {
|
||||
new (storage.buffer) T(std::move(*O.getPointer()));
|
||||
}
|
||||
}
|
||||
Optional &operator=(T &&y) {
|
||||
|
||||
OptionalStorage &operator=(T &&y) {
|
||||
if (hasVal)
|
||||
**this = std::move(y);
|
||||
*getPointer() = std::move(y);
|
||||
else {
|
||||
new (storage.buffer) T(std::move(y));
|
||||
hasVal = true;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
Optional &operator=(Optional &&O) {
|
||||
if (!O)
|
||||
OptionalStorage &operator=(OptionalStorage &&O) {
|
||||
if (!O.hasVal)
|
||||
reset();
|
||||
else {
|
||||
*this = std::move(*O);
|
||||
O.reset();
|
||||
*this = std::move(*O.getPointer());
|
||||
}
|
||||
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) {
|
||||
OptionalStorage &operator=(const T &y) {
|
||||
if (hasVal)
|
||||
**this = y;
|
||||
*getPointer() = y;
|
||||
else {
|
||||
new (storage.buffer) T(y);
|
||||
hasVal = true;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Optional &operator=(const Optional &O) {
|
||||
if (!O)
|
||||
OptionalStorage &operator=(const OptionalStorage &O) {
|
||||
if (!O.hasVal)
|
||||
reset();
|
||||
else
|
||||
*this = *O;
|
||||
*this = *O.getPointer();
|
||||
return *this;
|
||||
}
|
||||
|
||||
~OptionalStorage() { reset(); }
|
||||
|
||||
void reset() {
|
||||
if (hasVal) {
|
||||
(**this).~T();
|
||||
(*getPointer()).~T();
|
||||
hasVal = false;
|
||||
}
|
||||
}
|
||||
|
||||
~Optional() {
|
||||
reset();
|
||||
T *getPointer() {
|
||||
assert(hasVal);
|
||||
return reinterpret_cast<T *>(storage.buffer);
|
||||
}
|
||||
const T *getPointer() const {
|
||||
assert(hasVal);
|
||||
return reinterpret_cast<const T *>(storage.buffer);
|
||||
}
|
||||
};
|
||||
|
||||
#if !defined(__GNUC__) || defined(__clang__) // GCC up to GCC7 miscompiles this.
|
||||
/// Storage for trivially copyable types only.
|
||||
template <typename T> struct OptionalStorage<T, true> {
|
||||
AlignedCharArrayUnion<T> storage;
|
||||
bool hasVal = false;
|
||||
|
||||
OptionalStorage() = default;
|
||||
|
||||
OptionalStorage(const T &y) : hasVal(true) { new (storage.buffer) T(y); }
|
||||
OptionalStorage &operator=(const T &y) {
|
||||
*reinterpret_cast<T *>(storage.buffer) = y;
|
||||
hasVal = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
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(); }
|
||||
void reset() { hasVal = false; }
|
||||
};
|
||||
#endif
|
||||
} // namespace optional_detail
|
||||
|
||||
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 T> class Optional {
|
||||
optional_detail::OptionalStorage<T, isPodLike<T>::value> Storage;
|
||||
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
constexpr Optional() {}
|
||||
constexpr Optional(NoneType) {}
|
||||
|
||||
Optional(const T &y) : Storage(y) {}
|
||||
Optional(const Optional &O) = default;
|
||||
|
||||
Optional(T &&y) : Storage(std::forward<T>(y)) {}
|
||||
Optional(Optional &&O) = default;
|
||||
|
||||
Optional &operator=(T &&y) {
|
||||
Storage = std::move(y);
|
||||
return *this;
|
||||
}
|
||||
Optional &operator=(Optional &&O) = default;
|
||||
|
||||
/// Create a new object by constructing it in place with the given arguments.
|
||||
template <typename... ArgTypes> void emplace(ArgTypes &&... Args) {
|
||||
reset();
|
||||
Storage.hasVal = true;
|
||||
new (getPointer()) T(std::forward<ArgTypes>(Args)...);
|
||||
}
|
||||
|
||||
static inline Optional create(const T *y) {
|
||||
return y ? Optional(*y) : Optional();
|
||||
}
|
||||
|
||||
Optional &operator=(const T &y) {
|
||||
Storage = y;
|
||||
return *this;
|
||||
}
|
||||
Optional &operator=(const Optional &O) = default;
|
||||
|
||||
void reset() { Storage.reset(); }
|
||||
|
||||
const T *getPointer() const {
|
||||
assert(Storage.hasVal);
|
||||
return reinterpret_cast<const T *>(Storage.storage.buffer);
|
||||
}
|
||||
T *getPointer() {
|
||||
assert(Storage.hasVal);
|
||||
return reinterpret_cast<T *>(Storage.storage.buffer);
|
||||
}
|
||||
const T &getValue() const LLVM_LVALUE_FUNCTION { return *getPointer(); }
|
||||
T &getValue() LLVM_LVALUE_FUNCTION { return *getPointer(); }
|
||||
|
||||
explicit operator bool() const { return Storage.hasVal; }
|
||||
bool hasValue() const { return Storage.hasVal; }
|
||||
const T *operator->() const { return getPointer(); }
|
||||
T *operator->() { return getPointer(); }
|
||||
const T &operator*() const LLVM_LVALUE_FUNCTION { return *getPointer(); }
|
||||
T &operator*() LLVM_LVALUE_FUNCTION { return *getPointer(); }
|
||||
|
||||
template <typename U>
|
||||
LLVM_CONSTEXPR T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION {
|
||||
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()); }
|
||||
T &&getValue() && { return std::move(*getPointer()); }
|
||||
T &&operator*() && { return std::move(*getPointer()); }
|
||||
|
||||
template <typename U>
|
||||
T getValueOr(U &&value) && {
|
||||
@@ -144,24 +202,48 @@ public:
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename T> struct isPodLike;
|
||||
template <typename T> struct isPodLike<Optional<T> > {
|
||||
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, typename U>
|
||||
bool operator==(const Optional<T> &X, const Optional<U> &Y) {
|
||||
if (X && Y)
|
||||
return *X == *Y;
|
||||
return X.hasValue() == Y.hasValue();
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
bool operator!=(const Optional<T> &X, const Optional<U> &Y) {
|
||||
return !(X == Y);
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
bool operator<(const Optional<T> &X, const Optional<U> &Y) {
|
||||
if (X && Y)
|
||||
return *X < *Y;
|
||||
return X.hasValue() < Y.hasValue();
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
bool operator<=(const Optional<T> &X, const Optional<U> &Y) {
|
||||
return !(Y < X);
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
bool operator>(const Optional<T> &X, const Optional<U> &Y) {
|
||||
return Y < X;
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
bool operator>=(const Optional<T> &X, const Optional<U> &Y) {
|
||||
return !(X < Y);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool operator==(const Optional<T> &X, NoneType) {
|
||||
return !X.hasValue();
|
||||
return !X;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@@ -178,50 +260,86 @@ 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);
|
||||
template <typename T> bool operator<(const Optional<T> &X, NoneType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \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<(NoneType, const Optional<T> &X) {
|
||||
return X.hasValue();
|
||||
}
|
||||
|
||||
/// \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 !(None < X);
|
||||
}
|
||||
|
||||
/// \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<=(NoneType, const Optional<T> &X) {
|
||||
return !(X < None);
|
||||
}
|
||||
|
||||
template <typename T> bool operator>(const Optional<T> &X, NoneType) {
|
||||
return None < X;
|
||||
}
|
||||
|
||||
template <typename T> bool operator>(NoneType, const Optional<T> &X) {
|
||||
return X < None;
|
||||
}
|
||||
|
||||
template <typename T> bool operator>=(const Optional<T> &X, NoneType) {
|
||||
return None <= X;
|
||||
}
|
||||
|
||||
template <typename T> bool operator>=(NoneType, const Optional<T> &X) {
|
||||
return X <= None;
|
||||
}
|
||||
|
||||
template <typename T> bool operator==(const Optional<T> &X, const T &Y) {
|
||||
return X && *X == Y;
|
||||
}
|
||||
|
||||
template <typename T> bool operator==(const T &X, const Optional<T> &Y) {
|
||||
return Y && X == *Y;
|
||||
}
|
||||
|
||||
template <typename T> bool operator!=(const Optional<T> &X, const T &Y) {
|
||||
return !(X == Y);
|
||||
}
|
||||
|
||||
template <typename T> bool operator!=(const T &X, const Optional<T> &Y) {
|
||||
return !(X == Y);
|
||||
}
|
||||
|
||||
template <typename T> bool operator<(const Optional<T> &X, const T &Y) {
|
||||
return !X || *X < Y;
|
||||
}
|
||||
|
||||
template <typename T> bool operator<(const T &X, const Optional<T> &Y) {
|
||||
return Y && X < *Y;
|
||||
}
|
||||
|
||||
template <typename T> bool operator<=(const Optional<T> &X, const T &Y) {
|
||||
return !(Y < X);
|
||||
}
|
||||
|
||||
template <typename T> bool operator<=(const T &X, const Optional<T> &Y) {
|
||||
return !(Y < X);
|
||||
}
|
||||
|
||||
template <typename T> bool operator>(const Optional<T> &X, const T &Y) {
|
||||
return Y < X;
|
||||
}
|
||||
|
||||
template <typename T> bool operator>(const T &X, const Optional<T> &Y) {
|
||||
return Y < X;
|
||||
}
|
||||
|
||||
template <typename T> bool operator>=(const Optional<T> &X, const T &Y) {
|
||||
return !(X < Y);
|
||||
}
|
||||
|
||||
template <typename T> bool operator>=(const T &X, const Optional<T> &Y) {
|
||||
return !(X < Y);
|
||||
}
|
||||
|
||||
} // end wpi namespace
|
||||
|
||||
|
||||
@@ -16,20 +16,21 @@
|
||||
#ifndef WPIUTIL_WPI_PATH_H_
|
||||
#define WPIUTIL_WPI_PATH_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include "wpi/Twine.h"
|
||||
#include "wpi/iterator.h"
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
|
||||
namespace wpi {
|
||||
namespace sys {
|
||||
namespace path {
|
||||
|
||||
enum class Style { windows, posix, native };
|
||||
|
||||
/// @name Lexical Component Iterator
|
||||
/// @{
|
||||
|
||||
/// @brief Path iterator.
|
||||
/// Path iterator.
|
||||
///
|
||||
/// This is an input iterator that iterates over the individual components in
|
||||
/// \a path. The traversal order is as follows:
|
||||
@@ -49,67 +50,67 @@ namespace path {
|
||||
/// C:\foo\bar => C:,/,foo,bar
|
||||
/// @endcode
|
||||
class const_iterator
|
||||
: public std::iterator<std::input_iterator_tag, const StringRef> {
|
||||
: public iterator_facade_base<const_iterator, std::input_iterator_tag,
|
||||
const StringRef> {
|
||||
StringRef Path; ///< The entire path.
|
||||
StringRef Component; ///< The current component. Not necessarily in Path.
|
||||
size_t Position; ///< The iterators current position within Path.
|
||||
size_t Position; ///< The iterators current position within Path.
|
||||
Style S; ///< The path style to use.
|
||||
|
||||
// An end iterator has Position = Path.size() + 1.
|
||||
friend const_iterator begin(StringRef path);
|
||||
friend const_iterator begin(StringRef path, Style style);
|
||||
friend const_iterator end(StringRef path);
|
||||
|
||||
public:
|
||||
reference operator*() const { return Component; }
|
||||
pointer operator->() const { return &Component; }
|
||||
const_iterator& operator++(); // preincrement
|
||||
const_iterator &operator++(); // preincrement
|
||||
bool operator==(const const_iterator &RHS) const;
|
||||
bool operator!=(const const_iterator &RHS) const { return !(*this == RHS); }
|
||||
|
||||
/// @brief Difference in bytes between this and RHS.
|
||||
/// Difference in bytes between this and RHS.
|
||||
ptrdiff_t operator-(const const_iterator &RHS) const;
|
||||
};
|
||||
|
||||
/// @brief Reverse path iterator.
|
||||
/// Reverse path iterator.
|
||||
///
|
||||
/// This is an input iterator that iterates over the individual components in
|
||||
/// \a path in reverse order. The traversal order is exactly reversed from that
|
||||
/// of \a const_iterator
|
||||
class reverse_iterator
|
||||
: public std::iterator<std::input_iterator_tag, const StringRef> {
|
||||
: public iterator_facade_base<reverse_iterator, std::input_iterator_tag,
|
||||
const StringRef> {
|
||||
StringRef Path; ///< The entire path.
|
||||
StringRef Component; ///< The current component. Not necessarily in Path.
|
||||
size_t Position; ///< The iterators current position within Path.
|
||||
size_t Position; ///< The iterators current position within Path.
|
||||
Style S; ///< The path style to use.
|
||||
|
||||
friend reverse_iterator rbegin(StringRef path);
|
||||
friend reverse_iterator rbegin(StringRef path, Style style);
|
||||
friend reverse_iterator rend(StringRef path);
|
||||
|
||||
public:
|
||||
reference operator*() const { return Component; }
|
||||
pointer operator->() const { return &Component; }
|
||||
reverse_iterator& operator++(); // preincrement
|
||||
reverse_iterator &operator++(); // preincrement
|
||||
bool operator==(const reverse_iterator &RHS) const;
|
||||
bool operator!=(const reverse_iterator &RHS) const { return !(*this == RHS); }
|
||||
|
||||
/// @brief Difference in bytes between this and RHS.
|
||||
/// Difference in bytes between this and RHS.
|
||||
ptrdiff_t operator-(const reverse_iterator &RHS) const;
|
||||
};
|
||||
|
||||
/// @brief Get begin iterator over \a path.
|
||||
/// Get begin iterator over \a path.
|
||||
/// @param path Input path.
|
||||
/// @returns Iterator initialized with the first component of \a path.
|
||||
const_iterator begin(StringRef path);
|
||||
const_iterator begin(StringRef path, Style style = Style::native);
|
||||
|
||||
/// @brief Get end iterator over \a path.
|
||||
/// Get end iterator over \a path.
|
||||
/// @param path Input path.
|
||||
/// @returns Iterator initialized to the end of \a path.
|
||||
const_iterator end(StringRef path);
|
||||
|
||||
/// @brief Get reverse begin iterator over \a path.
|
||||
/// Get reverse begin iterator over \a path.
|
||||
/// @param path Input path.
|
||||
/// @returns Iterator initialized with the first reverse component of \a path.
|
||||
reverse_iterator rbegin(StringRef path);
|
||||
reverse_iterator rbegin(StringRef path, Style style = Style::native);
|
||||
|
||||
/// @brief Get reverse end iterator over \a path.
|
||||
/// Get reverse end iterator over \a path.
|
||||
/// @param path Input path.
|
||||
/// @returns Iterator initialized to the reverse end of \a path.
|
||||
reverse_iterator rend(StringRef path);
|
||||
@@ -118,7 +119,7 @@ reverse_iterator rend(StringRef path);
|
||||
/// @name Lexical Modifiers
|
||||
/// @{
|
||||
|
||||
/// @brief Remove the last component from \a path unless it is the root dir.
|
||||
/// Remove the last component from \a path unless it is the root dir.
|
||||
///
|
||||
/// @code
|
||||
/// directory/filename.cpp => directory/
|
||||
@@ -128,9 +129,9 @@ reverse_iterator rend(StringRef path);
|
||||
/// @endcode
|
||||
///
|
||||
/// @param path A path that is modified to not have a file component.
|
||||
void remove_filename(SmallVectorImpl<char> &path);
|
||||
void remove_filename(SmallVectorImpl<char> &path, Style style = Style::native);
|
||||
|
||||
/// @brief Replace the file extension of \a path with \a extension.
|
||||
/// Replace the file extension of \a path with \a extension.
|
||||
///
|
||||
/// @code
|
||||
/// ./filename.cpp => ./filename.extension
|
||||
@@ -142,9 +143,10 @@ void remove_filename(SmallVectorImpl<char> &path);
|
||||
/// @param extension The extension to be added. It may be empty. It may also
|
||||
/// optionally start with a '.', if it does not, one will be
|
||||
/// prepended.
|
||||
void replace_extension(SmallVectorImpl<char> &path, const Twine &extension);
|
||||
void replace_extension(SmallVectorImpl<char> &path, const Twine &extension,
|
||||
Style style = Style::native);
|
||||
|
||||
/// @brief Replace matching path prefix with another path.
|
||||
/// Replace matching path prefix with another path.
|
||||
///
|
||||
/// @code
|
||||
/// /foo, /old, /new => /foo
|
||||
@@ -158,10 +160,10 @@ void replace_extension(SmallVectorImpl<char> &path, const Twine &extension);
|
||||
/// @param OldPrefix The path prefix to strip from \a Path.
|
||||
/// @param NewPrefix The path prefix to replace \a NewPrefix with.
|
||||
void replace_path_prefix(SmallVectorImpl<char> &Path,
|
||||
const StringRef &OldPrefix,
|
||||
const StringRef &NewPrefix);
|
||||
const StringRef &OldPrefix, const StringRef &NewPrefix,
|
||||
Style style = Style::native);
|
||||
|
||||
/// @brief Append to path.
|
||||
/// Append to path.
|
||||
///
|
||||
/// @code
|
||||
/// /foo + bar/f => /foo/bar/f
|
||||
@@ -176,7 +178,10 @@ void append(SmallVectorImpl<char> &path, const Twine &a,
|
||||
const Twine &c = "",
|
||||
const Twine &d = "");
|
||||
|
||||
/// @brief Append to path.
|
||||
void append(SmallVectorImpl<char> &path, Style style, const Twine &a,
|
||||
const Twine &b = "", const Twine &c = "", const Twine &d = "");
|
||||
|
||||
/// Append to path.
|
||||
///
|
||||
/// @code
|
||||
/// /foo + [bar,f] => /foo/bar/f
|
||||
@@ -187,8 +192,8 @@ void append(SmallVectorImpl<char> &path, const Twine &a,
|
||||
/// @param path Set to \a path + [\a begin, \a end).
|
||||
/// @param begin Start of components to append.
|
||||
/// @param end One past the end of components to append.
|
||||
void append(SmallVectorImpl<char> &path,
|
||||
const_iterator begin, const_iterator end);
|
||||
void append(SmallVectorImpl<char> &path, const_iterator begin,
|
||||
const_iterator end, Style style = Style::native);
|
||||
|
||||
/// @}
|
||||
/// @name Transforms (or some other better name)
|
||||
@@ -200,20 +205,29 @@ void append(SmallVectorImpl<char> &path,
|
||||
///
|
||||
/// @param path A path that is transformed to native format.
|
||||
/// @param result Holds the result of the transformation.
|
||||
void native(const Twine &path, SmallVectorImpl<char> &result);
|
||||
void native(const Twine &path, SmallVectorImpl<char> &result,
|
||||
Style style = Style::native);
|
||||
|
||||
/// Convert path to the native form in place. This is used to give paths to
|
||||
/// users and operating system calls in the platform's normal way. For example,
|
||||
/// on Windows all '/' are converted to '\'.
|
||||
///
|
||||
/// @param path A path that is transformed to native format.
|
||||
void native(SmallVectorImpl<char> &path);
|
||||
void native(SmallVectorImpl<char> &path, Style style = Style::native);
|
||||
|
||||
/// Replaces backslashes with slashes if Windows.
|
||||
///
|
||||
/// @param path processed path
|
||||
/// @result The result of replacing backslashes with forward slashes if Windows.
|
||||
/// On Unix, this function is a no-op because backslashes are valid path
|
||||
/// chracters.
|
||||
std::string convert_to_slash(StringRef path, Style style = Style::native);
|
||||
|
||||
/// @}
|
||||
/// @name Lexical Observers
|
||||
/// @{
|
||||
|
||||
/// @brief Get root name.
|
||||
/// Get root name.
|
||||
///
|
||||
/// @code
|
||||
/// //net/hello => //net
|
||||
@@ -223,9 +237,9 @@ void native(SmallVectorImpl<char> &path);
|
||||
///
|
||||
/// @param path Input path.
|
||||
/// @result The root name of \a path if it has one, otherwise "".
|
||||
StringRef root_name(StringRef path);
|
||||
StringRef root_name(StringRef path, Style style = Style::native);
|
||||
|
||||
/// @brief Get root directory.
|
||||
/// Get root directory.
|
||||
///
|
||||
/// @code
|
||||
/// /goo/hello => /
|
||||
@@ -236,17 +250,17 @@ StringRef root_name(StringRef path);
|
||||
/// @param path Input path.
|
||||
/// @result The root directory of \a path if it has one, otherwise
|
||||
/// "".
|
||||
StringRef root_directory(StringRef path);
|
||||
StringRef root_directory(StringRef path, Style style = Style::native);
|
||||
|
||||
/// @brief Get root path.
|
||||
/// Get root path.
|
||||
///
|
||||
/// Equivalent to root_name + root_directory.
|
||||
///
|
||||
/// @param path Input path.
|
||||
/// @result The root path of \a path if it has one, otherwise "".
|
||||
StringRef root_path(StringRef path);
|
||||
StringRef root_path(StringRef path, Style style = Style::native);
|
||||
|
||||
/// @brief Get relative path.
|
||||
/// Get relative path.
|
||||
///
|
||||
/// @code
|
||||
/// C:\hello\world => hello\world
|
||||
@@ -256,9 +270,9 @@ StringRef root_path(StringRef path);
|
||||
///
|
||||
/// @param path Input path.
|
||||
/// @result The path starting after root_path if one exists, otherwise "".
|
||||
StringRef relative_path(StringRef path);
|
||||
StringRef relative_path(StringRef path, Style style = Style::native);
|
||||
|
||||
/// @brief Get parent path.
|
||||
/// Get parent path.
|
||||
///
|
||||
/// @code
|
||||
/// / => <empty>
|
||||
@@ -268,9 +282,9 @@ StringRef relative_path(StringRef path);
|
||||
///
|
||||
/// @param path Input path.
|
||||
/// @result The parent path of \a path if one exists, otherwise "".
|
||||
StringRef parent_path(StringRef path);
|
||||
StringRef parent_path(StringRef path, Style style = Style::native);
|
||||
|
||||
/// @brief Get filename.
|
||||
/// Get filename.
|
||||
///
|
||||
/// @code
|
||||
/// /foo.txt => foo.txt
|
||||
@@ -282,9 +296,9 @@ StringRef parent_path(StringRef path);
|
||||
/// @param path Input path.
|
||||
/// @result The filename part of \a path. This is defined as the last component
|
||||
/// of \a path.
|
||||
StringRef filename(StringRef path);
|
||||
StringRef filename(StringRef path, Style style = Style::native);
|
||||
|
||||
/// @brief Get stem.
|
||||
/// Get stem.
|
||||
///
|
||||
/// If filename contains a dot but not solely one or two dots, result is the
|
||||
/// substring of filename ending at (but not including) the last dot. Otherwise
|
||||
@@ -300,9 +314,9 @@ StringRef filename(StringRef path);
|
||||
///
|
||||
/// @param path Input path.
|
||||
/// @result The stem of \a path.
|
||||
StringRef stem(StringRef path);
|
||||
StringRef stem(StringRef path, Style style = Style::native);
|
||||
|
||||
/// @brief Get extension.
|
||||
/// Get extension.
|
||||
///
|
||||
/// If filename contains a dot but not solely one or two dots, result is the
|
||||
/// substring of filename starting at (and including) the last dot, and ending
|
||||
@@ -316,20 +330,20 @@ StringRef stem(StringRef path);
|
||||
///
|
||||
/// @param path Input path.
|
||||
/// @result The extension of \a path.
|
||||
StringRef extension(StringRef path);
|
||||
StringRef extension(StringRef path, Style style = Style::native);
|
||||
|
||||
/// @brief Check whether the given char is a path separator on the host OS.
|
||||
/// Check whether the given char is a path separator on the host OS.
|
||||
///
|
||||
/// @param value a character
|
||||
/// @result true if \a value is a path separator character on the host OS
|
||||
bool is_separator(char value);
|
||||
bool is_separator(char value, Style style = Style::native);
|
||||
|
||||
/// @brief Return the preferred separator for this platform.
|
||||
/// Return the preferred separator for this platform.
|
||||
///
|
||||
/// @result StringRef of the preferred separator, null-terminated.
|
||||
StringRef get_separator();
|
||||
StringRef get_separator(Style style = Style::native);
|
||||
|
||||
/// @brief Get the typical temporary directory for the system, e.g.,
|
||||
/// Get the typical temporary directory for the system, e.g.,
|
||||
/// "/var/tmp" or "C:/TEMP"
|
||||
///
|
||||
/// @param erasedOnReboot Whether to favor a path that is erased on reboot
|
||||
@@ -340,13 +354,13 @@ StringRef get_separator();
|
||||
/// @param result Holds the resulting path name.
|
||||
void system_temp_directory(bool erasedOnReboot, SmallVectorImpl<char> &result);
|
||||
|
||||
/// @brief Get the user's home directory.
|
||||
/// Get the user's home directory.
|
||||
///
|
||||
/// @param result Holds the resulting path name.
|
||||
/// @result True if a home directory is set, false otherwise.
|
||||
bool home_directory(SmallVectorImpl<char> &result);
|
||||
|
||||
/// @brief Get the user's cache directory.
|
||||
/// Get the user's cache directory.
|
||||
///
|
||||
/// Expect the resulting path to be a directory shared with other
|
||||
/// applications/services used by the user. Params \p Path1 to \p Path3 can be
|
||||
@@ -362,97 +376,99 @@ bool home_directory(SmallVectorImpl<char> &result);
|
||||
bool user_cache_directory(SmallVectorImpl<char> &Result, const Twine &Path1,
|
||||
const Twine &Path2 = "", const Twine &Path3 = "");
|
||||
|
||||
/// @brief Has root name?
|
||||
/// Has root name?
|
||||
///
|
||||
/// root_name != ""
|
||||
///
|
||||
/// @param path Input path.
|
||||
/// @result True if the path has a root name, false otherwise.
|
||||
bool has_root_name(const Twine &path);
|
||||
bool has_root_name(const Twine &path, Style style = Style::native);
|
||||
|
||||
/// @brief Has root directory?
|
||||
/// Has root directory?
|
||||
///
|
||||
/// root_directory != ""
|
||||
///
|
||||
/// @param path Input path.
|
||||
/// @result True if the path has a root directory, false otherwise.
|
||||
bool has_root_directory(const Twine &path);
|
||||
bool has_root_directory(const Twine &path, Style style = Style::native);
|
||||
|
||||
/// @brief Has root path?
|
||||
/// Has root path?
|
||||
///
|
||||
/// root_path != ""
|
||||
///
|
||||
/// @param path Input path.
|
||||
/// @result True if the path has a root path, false otherwise.
|
||||
bool has_root_path(const Twine &path);
|
||||
bool has_root_path(const Twine &path, Style style = Style::native);
|
||||
|
||||
/// @brief Has relative path?
|
||||
/// Has relative path?
|
||||
///
|
||||
/// relative_path != ""
|
||||
///
|
||||
/// @param path Input path.
|
||||
/// @result True if the path has a relative path, false otherwise.
|
||||
bool has_relative_path(const Twine &path);
|
||||
bool has_relative_path(const Twine &path, Style style = Style::native);
|
||||
|
||||
/// @brief Has parent path?
|
||||
/// Has parent path?
|
||||
///
|
||||
/// parent_path != ""
|
||||
///
|
||||
/// @param path Input path.
|
||||
/// @result True if the path has a parent path, false otherwise.
|
||||
bool has_parent_path(const Twine &path);
|
||||
bool has_parent_path(const Twine &path, Style style = Style::native);
|
||||
|
||||
/// @brief Has filename?
|
||||
/// Has filename?
|
||||
///
|
||||
/// filename != ""
|
||||
///
|
||||
/// @param path Input path.
|
||||
/// @result True if the path has a filename, false otherwise.
|
||||
bool has_filename(const Twine &path);
|
||||
bool has_filename(const Twine &path, Style style = Style::native);
|
||||
|
||||
/// @brief Has stem?
|
||||
/// Has stem?
|
||||
///
|
||||
/// stem != ""
|
||||
///
|
||||
/// @param path Input path.
|
||||
/// @result True if the path has a stem, false otherwise.
|
||||
bool has_stem(const Twine &path);
|
||||
bool has_stem(const Twine &path, Style style = Style::native);
|
||||
|
||||
/// @brief Has extension?
|
||||
/// Has extension?
|
||||
///
|
||||
/// extension != ""
|
||||
///
|
||||
/// @param path Input path.
|
||||
/// @result True if the path has a extension, false otherwise.
|
||||
bool has_extension(const Twine &path);
|
||||
bool has_extension(const Twine &path, Style style = Style::native);
|
||||
|
||||
/// @brief Is path absolute?
|
||||
/// Is path absolute?
|
||||
///
|
||||
/// @param path Input path.
|
||||
/// @result True if the path is absolute, false if it is not.
|
||||
bool is_absolute(const Twine &path);
|
||||
bool is_absolute(const Twine &path, Style style = Style::native);
|
||||
|
||||
/// @brief Is path relative?
|
||||
/// Is path relative?
|
||||
///
|
||||
/// @param path Input path.
|
||||
/// @result True if the path is relative, false if it is not.
|
||||
bool is_relative(const Twine &path);
|
||||
bool is_relative(const Twine &path, Style style = Style::native);
|
||||
|
||||
/// @brief Remove redundant leading "./" pieces and consecutive separators.
|
||||
/// Remove redundant leading "./" pieces and consecutive separators.
|
||||
///
|
||||
/// @param path Input path.
|
||||
/// @result The cleaned-up \a path.
|
||||
StringRef remove_leading_dotslash(StringRef path);
|
||||
StringRef remove_leading_dotslash(StringRef path, Style style = Style::native);
|
||||
|
||||
/// @brief In-place remove any './' and optionally '../' components from a path.
|
||||
/// In-place remove any './' and optionally '../' components from a path.
|
||||
///
|
||||
/// @param path processed path
|
||||
/// @param remove_dot_dot specify if '../' should be removed
|
||||
/// @param remove_dot_dot specify if '../' (except for leading "../") should be
|
||||
/// removed
|
||||
/// @result True if path was changed
|
||||
bool remove_dots(SmallVectorImpl<char> &path, bool remove_dot_dot = false);
|
||||
bool remove_dots(SmallVectorImpl<char> &path, bool remove_dot_dot = false,
|
||||
Style style = Style::native);
|
||||
|
||||
} // namespace path
|
||||
} // namespace sys
|
||||
} // namespace wpi
|
||||
} // end namespace path
|
||||
} // end namespace sys
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_PATH_H_
|
||||
#endif
|
||||
|
||||
@@ -12,21 +12,18 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_POINTERLIKETYPETRAITS_H
|
||||
#define LLVM_SUPPORT_POINTERLIKETYPETRAITS_H
|
||||
#ifndef WPIUTIL_WPI_POINTERLIKETYPETRAITS_H
|
||||
#define WPIUTIL_WPI_POINTERLIKETYPETRAITS_H
|
||||
|
||||
#include "wpi/AlignOf.h"
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <type_traits>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// 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
|
||||
};
|
||||
template <typename T> struct PointerLikeTypeTraits;
|
||||
|
||||
namespace detail {
|
||||
/// A tiny meta function to compute the log2 of a compile time constant.
|
||||
@@ -34,21 +31,36 @@ 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 a trait to check if T is pointer-like.
|
||||
template <typename T, typename U = void> struct HasPointerLikeTypeTraits {
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
// sizeof(T) is valid only for a complete T.
|
||||
template <typename T> struct HasPointerLikeTypeTraits<
|
||||
T, decltype((sizeof(PointerLikeTypeTraits<T>) + sizeof(T)), void())> {
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
template <typename T> struct IsPointerLike {
|
||||
static const bool value = HasPointerLikeTypeTraits<T>::value;
|
||||
};
|
||||
|
||||
template <typename T> struct IsPointerLike<T *> {
|
||||
static const bool value = true;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
// Provide PointerLikeTypeTraits for non-cvr pointers.
|
||||
template <typename T> class PointerLikeTypeTraits<T *> {
|
||||
public:
|
||||
template <typename T> struct PointerLikeTypeTraits<T *> {
|
||||
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
|
||||
};
|
||||
enum { NumLowBitsAvailable = detail::ConstantLog2<alignof(T)>::value };
|
||||
};
|
||||
|
||||
template <> class PointerLikeTypeTraits<void *> {
|
||||
public:
|
||||
template <> struct PointerLikeTypeTraits<void *> {
|
||||
static inline void *getAsVoidPointer(void *P) { return P; }
|
||||
static inline void *getFromVoidPointer(void *P) { return P; }
|
||||
|
||||
@@ -62,11 +74,23 @@ public:
|
||||
enum { NumLowBitsAvailable = 2 };
|
||||
};
|
||||
|
||||
// Provide PointerLikeTypeTraits for const things.
|
||||
template <typename T> struct PointerLikeTypeTraits<const T> {
|
||||
typedef PointerLikeTypeTraits<T> NonConst;
|
||||
|
||||
static inline const void *getAsVoidPointer(const T P) {
|
||||
return NonConst::getAsVoidPointer(P);
|
||||
}
|
||||
static inline const T getFromVoidPointer(const void *P) {
|
||||
return NonConst::getFromVoidPointer(const_cast<void *>(P));
|
||||
}
|
||||
enum { NumLowBitsAvailable = NonConst::NumLowBitsAvailable };
|
||||
};
|
||||
|
||||
// Provide PointerLikeTypeTraits for const pointers.
|
||||
template <typename T> class PointerLikeTypeTraits<const T *> {
|
||||
template <typename T> struct PointerLikeTypeTraits<const T *> {
|
||||
typedef PointerLikeTypeTraits<T *> NonConst;
|
||||
|
||||
public:
|
||||
static inline const void *getAsVoidPointer(const T *P) {
|
||||
return NonConst::getAsVoidPointer(const_cast<T *>(P));
|
||||
}
|
||||
@@ -77,8 +101,7 @@ public:
|
||||
};
|
||||
|
||||
// Provide PointerLikeTypeTraits for uintptr_t.
|
||||
template <> class PointerLikeTypeTraits<uintptr_t> {
|
||||
public:
|
||||
template <> struct PointerLikeTypeTraits<uintptr_t> {
|
||||
static inline void *getAsVoidPointer(uintptr_t P) {
|
||||
return reinterpret_cast<void *>(P);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,23 +12,23 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_SMALLPTRSET_H
|
||||
#define LLVM_ADT_SMALLPTRSET_H
|
||||
#ifndef WPIUTIL_WPI_SMALLPTRSET_H
|
||||
#define WPIUTIL_WPI_SMALLPTRSET_H
|
||||
|
||||
#include "wpi/Compiler.h"
|
||||
#include "wpi/PointerLikeTypeTraits.h"
|
||||
#include "wpi/type_traits.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
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.
|
||||
@@ -71,20 +71,25 @@ protected:
|
||||
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; }
|
||||
using size_type = unsigned;
|
||||
|
||||
SmallPtrSetImplBase &operator=(const SmallPtrSetImplBase &) = delete;
|
||||
|
||||
LLVM_NODISCARD bool empty() const { return size() == 0; }
|
||||
size_type size() const { return NumNonEmpty - NumTombstones; }
|
||||
|
||||
void clear() {
|
||||
@@ -103,6 +108,7 @@ public:
|
||||
|
||||
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.
|
||||
@@ -150,20 +156,36 @@ protected:
|
||||
/// 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 erase_imp(const void * Ptr) {
|
||||
const void *const *P = find_imp(Ptr);
|
||||
if (P == EndPointer())
|
||||
return false;
|
||||
|
||||
bool count_imp(const void * Ptr) const {
|
||||
const void **Loc = const_cast<const void **>(P);
|
||||
assert(*Loc == Ptr && "broken find!");
|
||||
*Loc = getTombstoneMarker();
|
||||
NumTombstones++;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Returns the raw pointer needed to construct an iterator. If element not
|
||||
/// found, this will be EndPointer. Otherwise, it will be a pointer to the
|
||||
/// slot which stores Ptr;
|
||||
const void *const * find_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;
|
||||
return APtr;
|
||||
return EndPointer();
|
||||
}
|
||||
|
||||
// Big set case.
|
||||
return *FindBucketFor(Ptr) == Ptr;
|
||||
auto *Bucket = FindBucketFor(Ptr);
|
||||
if (*Bucket == Ptr)
|
||||
return Bucket;
|
||||
return EndPointer();
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -177,8 +199,6 @@ private:
|
||||
/// 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.
|
||||
@@ -225,22 +245,30 @@ protected:
|
||||
*Bucket == SmallPtrSetImplBase::getTombstoneMarker()))
|
||||
++Bucket;
|
||||
}
|
||||
void RetreatIfNotValid() {
|
||||
assert(Bucket >= End);
|
||||
while (Bucket != End &&
|
||||
(Bucket[-1] == SmallPtrSetImplBase::getEmptyMarker() ||
|
||||
Bucket[-1] == SmallPtrSetImplBase::getTombstoneMarker())) {
|
||||
--Bucket;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// SmallPtrSetIterator - This implements a const_iterator for SmallPtrSet.
|
||||
template<typename PtrTy>
|
||||
template <typename PtrTy>
|
||||
class SmallPtrSetIterator : public SmallPtrSetIteratorImpl {
|
||||
typedef PointerLikeTypeTraits<PtrTy> PtrTraits;
|
||||
using PtrTraits = PointerLikeTypeTraits<PtrTy>;
|
||||
|
||||
public:
|
||||
typedef PtrTy value_type;
|
||||
typedef PtrTy reference;
|
||||
typedef PtrTy pointer;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
using value_type = PtrTy;
|
||||
using reference = PtrTy;
|
||||
using pointer = PtrTy;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
explicit SmallPtrSetIterator(const void *const *BP, const void *const *E)
|
||||
: SmallPtrSetIteratorImpl(BP, E) {}
|
||||
: SmallPtrSetIteratorImpl(BP, E) {}
|
||||
|
||||
// Most methods provided by baseclass.
|
||||
|
||||
@@ -256,7 +284,9 @@ public:
|
||||
}
|
||||
|
||||
SmallPtrSetIterator operator++(int) { // Postincrement
|
||||
SmallPtrSetIterator tmp = *this; ++*this; return tmp;
|
||||
SmallPtrSetIterator tmp = *this;
|
||||
++*this;
|
||||
return tmp;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -285,16 +315,16 @@ struct RoundUpToPowerOfTwo {
|
||||
enum { Val = RoundUpToPowerOfTwoH<N, (N&(N-1)) == 0>::Val };
|
||||
};
|
||||
|
||||
/// \brief A templated base class for \c SmallPtrSet which provides the
|
||||
/// 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;
|
||||
using ConstPtrType = typename add_const_past_pointer<PtrType>::type;
|
||||
using PtrTraits = PointerLikeTypeTraits<PtrType>;
|
||||
using ConstPtrTraits = PointerLikeTypeTraits<ConstPtrType>;
|
||||
|
||||
protected:
|
||||
// Constructors that forward to the base.
|
||||
@@ -307,8 +337,12 @@ protected:
|
||||
: SmallPtrSetImplBase(SmallStorage, SmallSize) {}
|
||||
|
||||
public:
|
||||
typedef SmallPtrSetIterator<PtrType> iterator;
|
||||
typedef SmallPtrSetIterator<PtrType> const_iterator;
|
||||
using iterator = SmallPtrSetIterator<PtrType>;
|
||||
using const_iterator = SmallPtrSetIterator<PtrType>;
|
||||
using key_type = ConstPtrType;
|
||||
using value_type = PtrType;
|
||||
|
||||
SmallPtrSetImpl(const SmallPtrSetImpl &) = delete;
|
||||
|
||||
/// 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
|
||||
@@ -316,7 +350,7 @@ public:
|
||||
/// 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);
|
||||
return std::make_pair(makeIterator(p.first), p.second);
|
||||
}
|
||||
|
||||
/// erase - If the set contains the specified pointer, remove it and return
|
||||
@@ -326,8 +360,9 @@ public:
|
||||
}
|
||||
|
||||
/// 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;
|
||||
size_type count(ConstPtrType Ptr) const { return find(Ptr) != end() ? 1 : 0; }
|
||||
iterator find(ConstPtrType Ptr) const {
|
||||
return makeIterator(find_imp(ConstPtrTraits::getAsVoidPointer(Ptr)));
|
||||
}
|
||||
|
||||
template <typename IterT>
|
||||
@@ -336,12 +371,19 @@ public:
|
||||
insert(*I);
|
||||
}
|
||||
|
||||
inline iterator begin() const {
|
||||
return iterator(CurArray, EndPointer());
|
||||
void insert(std::initializer_list<PtrType> IL) {
|
||||
insert(IL.begin(), IL.end());
|
||||
}
|
||||
inline iterator end() const {
|
||||
const void *const *End = EndPointer();
|
||||
return iterator(End, End);
|
||||
|
||||
iterator begin() const {
|
||||
return makeIterator(CurArray);
|
||||
}
|
||||
iterator end() const { return makeIterator(EndPointer()); }
|
||||
|
||||
private:
|
||||
/// Create an iterator that dereferences to same place as the given pointer.
|
||||
iterator makeIterator(const void *const *P) const {
|
||||
return iterator(P, EndPointer(), *this);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -356,7 +398,7 @@ class SmallPtrSet : public SmallPtrSetImpl<PtrType> {
|
||||
// DenseSet<> instead if you expect many elements in the set.
|
||||
static_assert(SmallSize <= 32, "SmallSize should be small");
|
||||
|
||||
typedef SmallPtrSetImpl<PtrType> BaseT;
|
||||
using BaseT = SmallPtrSetImpl<PtrType>;
|
||||
|
||||
// Make sure that SmallSize is a power of two, round up if not.
|
||||
enum { SmallSizePowTwo = RoundUpToPowerOfTwo<SmallSize>::Val };
|
||||
@@ -374,6 +416,11 @@ public:
|
||||
this->insert(I, E);
|
||||
}
|
||||
|
||||
SmallPtrSet(std::initializer_list<PtrType> IL)
|
||||
: BaseT(SmallStorage, SmallSizePowTwo) {
|
||||
this->insert(IL.begin(), IL.end());
|
||||
}
|
||||
|
||||
SmallPtrSet<PtrType, SmallSize> &
|
||||
operator=(const SmallPtrSet<PtrType, SmallSize> &RHS) {
|
||||
if (&RHS != this)
|
||||
@@ -381,26 +428,36 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
SmallPtrSet<PtrType, SmallSize>&
|
||||
SmallPtrSet<PtrType, SmallSize> &
|
||||
operator=(SmallPtrSet<PtrType, SmallSize> &&RHS) {
|
||||
if (&RHS != this)
|
||||
this->MoveFrom(SmallSizePowTwo, std::move(RHS));
|
||||
return *this;
|
||||
}
|
||||
|
||||
SmallPtrSet<PtrType, SmallSize> &
|
||||
operator=(std::initializer_list<PtrType> IL) {
|
||||
this->clear();
|
||||
this->insert(IL.begin(), IL.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// swap - Swaps the elements of two sets.
|
||||
void swap(SmallPtrSet<PtrType, SmallSize> &RHS) {
|
||||
SmallPtrSetImplBase::swap(RHS);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
namespace std {
|
||||
|
||||
/// Implement std::swap in terms of SmallPtrSet swap.
|
||||
template<class T, unsigned N>
|
||||
inline void swap(wpi::SmallPtrSet<T, N> &LHS, wpi::SmallPtrSet<T, N> &RHS) {
|
||||
LHS.swap(RHS);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
} // end namespace std
|
||||
|
||||
#endif // LLVM_ADT_SMALLPTRSET_H
|
||||
|
||||
@@ -11,13 +11,17 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_SMALLSET_H
|
||||
#define LLVM_ADT_SMALLSET_H
|
||||
#ifndef WPIUTIL_WPI_SMALLSET_H
|
||||
#define WPIUTIL_WPI_SMALLSET_H
|
||||
|
||||
#include "wpi/None.h"
|
||||
#include "wpi/SmallPtrSet.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/Compiler.h"
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <set>
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
@@ -28,15 +32,16 @@ namespace wpi {
|
||||
///
|
||||
/// 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> >
|
||||
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;
|
||||
|
||||
using VIterator = typename SmallVector<T, N>::const_iterator;
|
||||
using mutable_iterator = typename SmallVector<T, N>::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
|
||||
@@ -44,10 +49,11 @@ class SmallSet {
|
||||
static_assert(N <= 32, "N should be small");
|
||||
|
||||
public:
|
||||
typedef size_t size_type;
|
||||
SmallSet() {}
|
||||
using size_type = size_t;
|
||||
|
||||
bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const {
|
||||
SmallSet() = default;
|
||||
|
||||
LLVM_NODISCARD bool empty() const {
|
||||
return Vector.empty() && Set.empty();
|
||||
}
|
||||
|
||||
@@ -133,4 +139,4 @@ class SmallSet<PointeeType*, N> : public SmallPtrSet<PointeeType*, N> {};
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif
|
||||
#endif // LLVM_ADT_SMALLSET_H
|
||||
|
||||
@@ -11,11 +11,12 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_SMALLSTRING_H
|
||||
#define LLVM_ADT_SMALLSTRING_H
|
||||
#ifndef WPIUTIL_WPI_SMALLSTRING_H
|
||||
#define WPIUTIL_WPI_SMALLSTRING_H
|
||||
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/StringRef.h"
|
||||
#include <cstddef>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
@@ -25,7 +26,7 @@ template<unsigned InternalLen>
|
||||
class SmallString : public SmallVector<char, InternalLen> {
|
||||
public:
|
||||
/// Default ctor - Initialize to empty.
|
||||
SmallString() {}
|
||||
SmallString() = default;
|
||||
|
||||
/// Initialize from a StringRef.
|
||||
SmallString(StringRef S) : SmallVector<char, InternalLen>(S.begin(), S.end()) {}
|
||||
@@ -79,7 +80,6 @@ public:
|
||||
SmallVectorImpl<char>::append(NumInputs, Elt);
|
||||
}
|
||||
|
||||
|
||||
/// Append from a StringRef.
|
||||
void append(StringRef RHS) {
|
||||
SmallVectorImpl<char>::append(RHS.begin(), RHS.end());
|
||||
@@ -292,6 +292,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
} // end namespace wpi
|
||||
|
||||
#endif
|
||||
#endif // LLVM_ADT_SMALLSTRING_H
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_SMALLVECTOR_H
|
||||
#define LLVM_ADT_SMALLVECTOR_H
|
||||
#ifndef WPIUTIL_WPI_SMALLVECTOR_H
|
||||
#define WPIUTIL_WPI_SMALLVECTOR_H
|
||||
|
||||
// This file uses std::memcpy() to copy std::pair<unsigned int, unsigned int>.
|
||||
// That type is POD, but the standard doesn't guarantee that. GCC doesn't treat
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "wpi/AlignOf.h"
|
||||
#include "wpi/Compiler.h"
|
||||
#include "wpi/MathExtras.h"
|
||||
#include "wpi/memory.h"
|
||||
#include "wpi/type_traits.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
@@ -35,6 +36,9 @@
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
@@ -62,11 +66,9 @@ public:
|
||||
return size_t((char*)CapacityX - (char*)BeginX);
|
||||
}
|
||||
|
||||
bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const { return BeginX == EndX; }
|
||||
LLVM_NODISCARD bool 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.
|
||||
@@ -78,7 +80,7 @@ private:
|
||||
// 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 wpi::AlignedCharArrayUnion<T> U;
|
||||
using U = AlignedCharArrayUnion<T>;
|
||||
U FirstEl;
|
||||
// Space after 'FirstEl' is clobbered, do not add any instance vars after it.
|
||||
|
||||
@@ -101,37 +103,44 @@ protected:
|
||||
}
|
||||
|
||||
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;
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
using value_type = T;
|
||||
using iterator = T *;
|
||||
using const_iterator = const T *;
|
||||
|
||||
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
||||
typedef std::reverse_iterator<iterator> reverse_iterator;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
|
||||
typedef T &reference;
|
||||
typedef const T &const_reference;
|
||||
typedef T *pointer;
|
||||
typedef const T *const_pointer;
|
||||
using reference = T &;
|
||||
using const_reference = const T &;
|
||||
using pointer = T *;
|
||||
using const_pointer = const T *;
|
||||
|
||||
// forward iterator creation methods.
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
iterator begin() { return (iterator)this->BeginX; }
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
const_iterator begin() const { return (const_iterator)this->BeginX; }
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
iterator end() { return (iterator)this->EndX; }
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
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:
|
||||
|
||||
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());}
|
||||
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
size_type size() const { return end()-begin(); }
|
||||
size_type max_size() const { return size_type(-1) / sizeof(T); }
|
||||
|
||||
@@ -143,10 +152,12 @@ public:
|
||||
/// Return a pointer to the vector's buffer, even if empty().
|
||||
const_pointer data() const { return const_pointer(begin()); }
|
||||
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
reference operator[](size_type idx) {
|
||||
assert(idx < size());
|
||||
return begin()[idx];
|
||||
}
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
const_reference operator[](size_type idx) const {
|
||||
assert(idx < size());
|
||||
return begin()[idx];
|
||||
@@ -235,7 +246,7 @@ void SmallVectorTemplateBase<T, isPodLike>::grow(size_t MinSize) {
|
||||
size_t NewCapacity = size_t(NextPowerOf2(CurCapacity+2));
|
||||
if (NewCapacity < MinSize)
|
||||
NewCapacity = MinSize;
|
||||
T *NewElts = static_cast<T*>(malloc(NewCapacity*sizeof(T)));
|
||||
T *NewElts = static_cast<T*>(CheckedMalloc(NewCapacity*sizeof(T)));
|
||||
|
||||
// Move the elements over.
|
||||
this->uninitialized_move(this->begin(), this->end(), NewElts);
|
||||
@@ -299,6 +310,7 @@ protected:
|
||||
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))
|
||||
@@ -312,18 +324,16 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// 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;
|
||||
using SuperClass = SmallVectorTemplateBase<T, isPodLike<T>::value>;
|
||||
|
||||
SmallVectorImpl(const SmallVectorImpl&) = delete;
|
||||
public:
|
||||
typedef typename SuperClass::iterator iterator;
|
||||
typedef typename SuperClass::const_iterator const_iterator;
|
||||
typedef typename SuperClass::size_type size_type;
|
||||
using iterator = typename SuperClass::iterator;
|
||||
using const_iterator = typename SuperClass::const_iterator;
|
||||
using size_type = typename SuperClass::size_type;
|
||||
|
||||
protected:
|
||||
// Default ctor - Initialize to empty.
|
||||
@@ -332,16 +342,15 @@ protected:
|
||||
}
|
||||
|
||||
public:
|
||||
~SmallVectorImpl() {
|
||||
// Destroy the constructed elements in the vector.
|
||||
this->destroy_range(this->begin(), this->end());
|
||||
SmallVectorImpl(const SmallVectorImpl &) = delete;
|
||||
|
||||
~SmallVectorImpl() {
|
||||
// Subclass has already destructed this vector's elements.
|
||||
// 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;
|
||||
@@ -377,7 +386,7 @@ public:
|
||||
this->grow(N);
|
||||
}
|
||||
|
||||
T LLVM_ATTRIBUTE_UNUSED_RESULT pop_back_val() {
|
||||
LLVM_NODISCARD T pop_back_val() {
|
||||
T Result = ::std::move(this->back());
|
||||
this->pop_back();
|
||||
return Result;
|
||||
@@ -386,7 +395,10 @@ public:
|
||||
void swap(SmallVectorImpl &RHS);
|
||||
|
||||
/// Add the specified range to the end of the SmallVector.
|
||||
template<typename in_iter>
|
||||
template <typename in_iter,
|
||||
typename = typename std::enable_if<std::is_convertible<
|
||||
typename std::iterator_traits<in_iter>::iterator_category,
|
||||
std::input_iterator_tag>::value>::type>
|
||||
void append(in_iter in_start, in_iter in_end) {
|
||||
size_type NumInputs = std::distance(in_start, in_end);
|
||||
// Grow allocated space if needed.
|
||||
@@ -413,6 +425,9 @@ public:
|
||||
append(IL.begin(), IL.end());
|
||||
}
|
||||
|
||||
// FIXME: Consider assigning over existing elements, rather than clearing &
|
||||
// re-initializing them - for all assign(...) variants.
|
||||
|
||||
void assign(size_type NumElts, const T &Elt) {
|
||||
clear();
|
||||
if (this->capacity() < NumElts)
|
||||
@@ -421,6 +436,15 @@ public:
|
||||
std::uninitialized_fill(this->begin(), this->end(), Elt);
|
||||
}
|
||||
|
||||
template <typename in_iter,
|
||||
typename = typename std::enable_if<std::is_convertible<
|
||||
typename std::iterator_traits<in_iter>::iterator_category,
|
||||
std::input_iterator_tag>::value>::type>
|
||||
void assign(in_iter in_start, in_iter in_end) {
|
||||
clear();
|
||||
append(in_start, in_end);
|
||||
}
|
||||
|
||||
void assign(std::initializer_list<T> IL) {
|
||||
clear();
|
||||
append(IL);
|
||||
@@ -569,7 +593,10 @@ public:
|
||||
return I;
|
||||
}
|
||||
|
||||
template<typename ItTy>
|
||||
template <typename ItTy,
|
||||
typename = typename std::enable_if<std::is_convertible<
|
||||
typename std::iterator_traits<ItTy>::iterator_category,
|
||||
std::input_iterator_tag>::value>::type>
|
||||
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();
|
||||
@@ -669,7 +696,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
void SmallVectorImpl<T>::swap(SmallVectorImpl<T> &RHS) {
|
||||
if (this == &RHS) return;
|
||||
@@ -842,8 +868,13 @@ 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) {
|
||||
SmallVector() : SmallVectorImpl<T>(N) {}
|
||||
|
||||
~SmallVector() {
|
||||
// Destroy the constructed elements in the vector.
|
||||
this->destroy_range(this->begin(), this->end());
|
||||
}
|
||||
|
||||
explicit SmallVector(size_t Size, const T &Value = T())
|
||||
@@ -851,13 +882,16 @@ public:
|
||||
this->assign(Size, Value);
|
||||
}
|
||||
|
||||
template<typename ItTy>
|
||||
template <typename ItTy,
|
||||
typename = typename std::enable_if<std::is_convertible<
|
||||
typename std::iterator_traits<ItTy>::iterator_category,
|
||||
std::input_iterator_tag>::value>::type>
|
||||
SmallVector(ItTy S, ItTy E) : SmallVectorImpl<T>(N) {
|
||||
this->append(S, E);
|
||||
}
|
||||
|
||||
template <typename RangeTy>
|
||||
explicit SmallVector(const wpi::iterator_range<RangeTy> R)
|
||||
explicit SmallVector(const iterator_range<RangeTy> &R)
|
||||
: SmallVectorImpl<T>(N) {
|
||||
this->append(R.begin(), R.end());
|
||||
}
|
||||
@@ -881,16 +915,16 @@ public:
|
||||
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=(SmallVector &&RHS) {
|
||||
SmallVectorImpl<T>::operator=(::std::move(RHS));
|
||||
return *this;
|
||||
}
|
||||
|
||||
const SmallVector &operator=(SmallVectorImpl<T> &&RHS) {
|
||||
SmallVectorImpl<T>::operator=(::std::move(RHS));
|
||||
return *this;
|
||||
@@ -902,14 +936,15 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, unsigned N>
|
||||
static inline size_t capacity_in_bytes(const SmallVector<T, N> &X) {
|
||||
template <typename T, unsigned N>
|
||||
inline size_t capacity_in_bytes(const SmallVector<T, N> &X) {
|
||||
return X.capacity_in_bytes();
|
||||
}
|
||||
|
||||
} // End wpi namespace
|
||||
} // end namespace wpi
|
||||
|
||||
namespace std {
|
||||
|
||||
/// Implement std::swap in terms of SmallVector swap.
|
||||
template<typename T>
|
||||
inline void
|
||||
@@ -923,6 +958,7 @@ namespace std {
|
||||
swap(wpi::SmallVector<T, N> &LHS, wpi::SmallVector<T, N> &RHS) {
|
||||
LHS.swap(RHS);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
} // end namespace std
|
||||
|
||||
#endif // LLVM_ADT_SMALLVECTOR_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//===-- llvm/ADT/StringExtras.h - Useful string functions -------*- C++ -*-===//
|
||||
//===- llvm/ADT/StringExtras.h - Useful string functions --------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@@ -11,40 +11,88 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_STRINGEXTRAS_H
|
||||
#define LLVM_ADT_STRINGEXTRAS_H
|
||||
#ifndef WPIUTIL_WPI_STRINGEXTRAS_H
|
||||
#define WPIUTIL_WPI_STRINGEXTRAS_H
|
||||
|
||||
#include "wpi/ArrayRef.h"
|
||||
#include "wpi/SmallString.h"
|
||||
#include "wpi/StringRef.h"
|
||||
#include "wpi/Twine.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
template<typename T> class SmallVectorImpl;
|
||||
class raw_ostream;
|
||||
|
||||
/// 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) {
|
||||
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");
|
||||
inline StringRef toStringRef(bool B) { return StringRef(B ? "true" : "false"); }
|
||||
|
||||
/// Construct a string ref from an array ref of unsigned chars.
|
||||
inline StringRef toStringRef(ArrayRef<uint8_t> Input) {
|
||||
return StringRef(reinterpret_cast<const char *>(Input.begin()), Input.size());
|
||||
}
|
||||
|
||||
/// Construct a string ref from an array ref of unsigned chars.
|
||||
inline ArrayRef<uint8_t> arrayRefFromStringRef(StringRef Input) {
|
||||
return {Input.bytes_begin(), Input.bytes_end()};
|
||||
}
|
||||
|
||||
/// 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) {
|
||||
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) {
|
||||
/// Checks if character \p C is one of the 10 decimal digits.
|
||||
inline bool isDigit(char C) { return C >= '0' && C <= '9'; }
|
||||
|
||||
/// Checks if character \p C is a hexadecimal numeric character.
|
||||
inline bool isHexDigit(char C) { return hexDigitValue(C) != -1U; }
|
||||
|
||||
/// Checks if character \p C is a valid letter as classified by "C" locale.
|
||||
inline bool isAlpha(char C) {
|
||||
return ('a' <= C && C <= 'z') || ('A' <= C && C <= 'Z');
|
||||
}
|
||||
|
||||
/// Checks whether character \p C is either a decimal digit or an uppercase or
|
||||
/// lowercase letter as classified by "C" locale.
|
||||
inline bool isAlnum(char C) { return isAlpha(C) || isDigit(C); }
|
||||
|
||||
/// Returns the corresponding lowercase character if \p x is uppercase.
|
||||
inline char toLower(char x) {
|
||||
if (x >= 'A' && x <= 'Z')
|
||||
return x - 'A' + 'a';
|
||||
return x;
|
||||
}
|
||||
|
||||
/// Returns the corresponding uppercase character if \p x is lowercase.
|
||||
inline char toUpper(char x) {
|
||||
if (x >= 'a' && x <= 'z')
|
||||
return x - 'a' + 'A';
|
||||
return x;
|
||||
}
|
||||
|
||||
inline std::string utohexstr(uint64_t X, bool LowerCase = false) {
|
||||
char Buffer[17];
|
||||
char *BufPtr = std::end(Buffer);
|
||||
|
||||
@@ -61,7 +109,7 @@ static inline std::string utohexstr(uint64_t X, bool LowerCase = false) {
|
||||
|
||||
/// 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) {
|
||||
inline std::string toHex(StringRef Input) {
|
||||
static const char *const LUT = "0123456789ABCDEF";
|
||||
size_t Length = Input.size();
|
||||
|
||||
@@ -75,7 +123,74 @@ static inline std::string toHex(StringRef Input) {
|
||||
return Output;
|
||||
}
|
||||
|
||||
static inline std::string utostr(uint64_t X, bool isNeg = false) {
|
||||
inline std::string toHex(ArrayRef<uint8_t> Input) {
|
||||
return toHex(toStringRef(Input));
|
||||
}
|
||||
|
||||
inline uint8_t hexFromNibbles(char MSB, char LSB) {
|
||||
unsigned U1 = hexDigitValue(MSB);
|
||||
unsigned U2 = hexDigitValue(LSB);
|
||||
assert(U1 != -1U && U2 != -1U);
|
||||
|
||||
return static_cast<uint8_t>((U1 << 4) | U2);
|
||||
}
|
||||
|
||||
/// Convert hexadecimal string \p Input to its binary representation.
|
||||
/// The return string is half the size of \p Input.
|
||||
inline std::string fromHex(StringRef Input) {
|
||||
if (Input.empty())
|
||||
return std::string();
|
||||
|
||||
std::string Output;
|
||||
Output.reserve((Input.size() + 1) / 2);
|
||||
if (Input.size() % 2 == 1) {
|
||||
Output.push_back(hexFromNibbles('0', Input.front()));
|
||||
Input = Input.drop_front();
|
||||
}
|
||||
|
||||
assert(Input.size() % 2 == 0);
|
||||
while (!Input.empty()) {
|
||||
uint8_t Hex = hexFromNibbles(Input[0], Input[1]);
|
||||
Output.push_back(Hex);
|
||||
Input = Input.drop_front(2);
|
||||
}
|
||||
return Output;
|
||||
}
|
||||
|
||||
/// Convert the string \p S to an integer of the specified type using
|
||||
/// the radix \p Base. If \p Base is 0, auto-detects the radix.
|
||||
/// Returns true if the number was successfully converted, false otherwise.
|
||||
template <typename N> bool to_integer(StringRef S, N &Num, unsigned Base = 0) {
|
||||
return !S.getAsInteger(Base, Num);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template <typename N>
|
||||
inline bool to_float(const Twine &T, N &Num, N (*StrTo)(const char *, char **)) {
|
||||
SmallString<32> Storage;
|
||||
StringRef S = T.toNullTerminatedStringRef(Storage);
|
||||
char *End;
|
||||
N Temp = StrTo(S.data(), &End);
|
||||
if (*End != '\0')
|
||||
return false;
|
||||
Num = Temp;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool to_float(const Twine &T, float &Num) {
|
||||
return detail::to_float(T, Num, strtof);
|
||||
}
|
||||
|
||||
inline bool to_float(const Twine &T, double &Num) {
|
||||
return detail::to_float(T, Num, strtod);
|
||||
}
|
||||
|
||||
inline bool to_float(const Twine &T, long double &Num) {
|
||||
return detail::to_float(T, Num, strtold);
|
||||
}
|
||||
|
||||
inline std::string utostr(uint64_t X, bool isNeg = false) {
|
||||
char Buffer[21];
|
||||
char *BufPtr = std::end(Buffer);
|
||||
|
||||
@@ -90,8 +205,7 @@ static inline std::string utostr(uint64_t X, bool isNeg = false) {
|
||||
return std::string(BufPtr, std::end(Buffer));
|
||||
}
|
||||
|
||||
|
||||
static inline std::string itostr(int64_t X) {
|
||||
inline std::string itostr(int64_t X) {
|
||||
if (X < 0)
|
||||
return utostr(static_cast<uint64_t>(-X), true);
|
||||
else
|
||||
@@ -132,7 +246,7 @@ static inline unsigned HashString(StringRef Str, unsigned Result = 0) {
|
||||
}
|
||||
|
||||
/// Returns the English suffix for an ordinal integer (-st, -nd, -rd, -th).
|
||||
static inline StringRef getOrdinalSuffix(unsigned Val) {
|
||||
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) {
|
||||
@@ -150,6 +264,15 @@ static inline StringRef getOrdinalSuffix(unsigned Val) {
|
||||
}
|
||||
}
|
||||
|
||||
/// PrintEscapedString - Print each character of the specified string, escaping
|
||||
/// it if it is not printable or if it is an escape char.
|
||||
void PrintEscapedString(StringRef Name, raw_ostream &Out);
|
||||
|
||||
/// printLowerCase - Print each character as lowercase if it is uppercase.
|
||||
void printLowerCase(StringRef String, raw_ostream &Out);
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename IteratorT>
|
||||
inline std::string join_impl(IteratorT Begin, IteratorT End,
|
||||
StringRef Separator, std::input_iterator_tag) {
|
||||
@@ -184,14 +307,74 @@ inline std::string join_impl(IteratorT Begin, IteratorT End,
|
||||
return S;
|
||||
}
|
||||
|
||||
template <typename Sep>
|
||||
inline void join_items_impl(std::string &Result, Sep Separator) {}
|
||||
|
||||
template <typename Sep, typename Arg>
|
||||
inline void join_items_impl(std::string &Result, Sep Separator,
|
||||
const Arg &Item) {
|
||||
Result += Item;
|
||||
}
|
||||
|
||||
template <typename Sep, typename Arg1, typename... Args>
|
||||
inline void join_items_impl(std::string &Result, Sep Separator, const Arg1 &A1,
|
||||
Args &&... Items) {
|
||||
Result += A1;
|
||||
Result += Separator;
|
||||
join_items_impl(Result, Separator, std::forward<Args>(Items)...);
|
||||
}
|
||||
|
||||
inline size_t join_one_item_size(char C) { return 1; }
|
||||
inline size_t join_one_item_size(const char *S) { return S ? ::strlen(S) : 0; }
|
||||
|
||||
template <typename T> inline size_t join_one_item_size(const T &Str) {
|
||||
return Str.size();
|
||||
}
|
||||
|
||||
inline size_t join_items_size() { return 0; }
|
||||
|
||||
template <typename A1> inline size_t join_items_size(const A1 &A) {
|
||||
return join_one_item_size(A);
|
||||
}
|
||||
template <typename A1, typename... Args>
|
||||
inline size_t join_items_size(const A1 &A, Args &&... Items) {
|
||||
return join_one_item_size(A) + join_items_size(std::forward<Args>(Items)...);
|
||||
}
|
||||
|
||||
} // end namespace detail
|
||||
|
||||
/// 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());
|
||||
using tag = typename std::iterator_traits<IteratorT>::iterator_category;
|
||||
return detail::join_impl(Begin, End, Separator, tag());
|
||||
}
|
||||
|
||||
} // End wpi namespace
|
||||
/// Joins the strings in the range [R.begin(), R.end()), adding Separator
|
||||
/// between the elements.
|
||||
template <typename Range>
|
||||
inline std::string join(Range &&R, StringRef Separator) {
|
||||
return join(R.begin(), R.end(), Separator);
|
||||
}
|
||||
|
||||
#endif
|
||||
/// Joins the strings in the parameter pack \p Items, adding \p Separator
|
||||
/// between the elements. All arguments must be implicitly convertible to
|
||||
/// std::string, or there should be an overload of std::string::operator+=()
|
||||
/// that accepts the argument explicitly.
|
||||
template <typename Sep, typename... Args>
|
||||
inline std::string join_items(Sep Separator, Args &&... Items) {
|
||||
std::string Result;
|
||||
if (sizeof...(Items) == 0)
|
||||
return Result;
|
||||
|
||||
size_t NS = detail::join_one_item_size(Separator);
|
||||
size_t NI = detail::join_items_size(std::forward<Args>(Items)...);
|
||||
Result.reserve(NI + (sizeof...(Items) - 1) * NS + 1);
|
||||
detail::join_items_impl(Result, Separator, std::forward<Args>(Items)...);
|
||||
return Result;
|
||||
}
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // LLVM_ADT_STRINGEXTRAS_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//===--- StringMap.h - String Hash table map interface ----------*- C++ -*-===//
|
||||
//===- StringMap.h - String Hash table map interface ------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@@ -11,33 +11,40 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_STRINGMAP_H
|
||||
#define LLVM_ADT_STRINGMAP_H
|
||||
#ifndef WPIUTIL_WPI_STRINGMAP_H
|
||||
#define WPIUTIL_WPI_STRINGMAP_H
|
||||
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/StringRef.h"
|
||||
#include "wpi/iterator.h"
|
||||
#include "wpi/iterator_range.h"
|
||||
#include "wpi/PointerLikeTypeTraits.h"
|
||||
#include "wpi/deprecated.h"
|
||||
#include "wpi/memory.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
template<typename ValueT>
|
||||
class StringMapConstIterator;
|
||||
template<typename ValueT>
|
||||
class StringMapIterator;
|
||||
template<typename ValueTy>
|
||||
class StringMapEntry;
|
||||
|
||||
template<typename ValueTy> class StringMapConstIterator;
|
||||
template<typename ValueTy> class StringMapIterator;
|
||||
template<typename ValueTy> class StringMapKeyIterator;
|
||||
template<typename ValueTy> class StringMapEntry;
|
||||
|
||||
/// StringMapEntryBase - Shared base class of StringMapEntry instances.
|
||||
class StringMapEntryBase {
|
||||
unsigned StrLen;
|
||||
size_t StrLen;
|
||||
|
||||
public:
|
||||
explicit StringMapEntryBase(unsigned Len) : StrLen(Len) {}
|
||||
explicit StringMapEntryBase(size_t Len) : StrLen(Len) {}
|
||||
|
||||
unsigned getKeyLength() const { return StrLen; }
|
||||
size_t getKeyLength() const { return StrLen; }
|
||||
};
|
||||
|
||||
/// StringMapImpl - This is the base class of StringMap that is shared among
|
||||
@@ -47,17 +54,15 @@ 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;
|
||||
StringMapEntryBase **TheTable = nullptr;
|
||||
unsigned NumBuckets = 0;
|
||||
unsigned NumItems = 0;
|
||||
unsigned NumTombstones = 0;
|
||||
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) {}
|
||||
: ItemSize(itemSize) {}
|
||||
StringMapImpl(StringMapImpl &&RHS)
|
||||
: TheTable(RHS.TheTable), NumBuckets(RHS.NumBuckets),
|
||||
NumItems(RHS.NumItems), NumTombstones(RHS.NumTombstones),
|
||||
@@ -121,16 +126,15 @@ public:
|
||||
/// and data.
|
||||
template<typename ValueTy>
|
||||
class StringMapEntry : public StringMapEntryBase {
|
||||
StringMapEntry(StringMapEntry &E) = delete;
|
||||
|
||||
public:
|
||||
ValueTy second;
|
||||
|
||||
explicit StringMapEntry(unsigned strLen)
|
||||
explicit StringMapEntry(size_t strLen)
|
||||
: StringMapEntryBase(strLen), second() {}
|
||||
template <typename... InitTy>
|
||||
StringMapEntry(unsigned strLen, InitTy &&... InitVals)
|
||||
StringMapEntry(size_t strLen, InitTy &&... InitVals)
|
||||
: StringMapEntryBase(strLen), second(std::forward<InitTy>(InitVals)...) {}
|
||||
StringMapEntry(StringMapEntry &E) = delete;
|
||||
|
||||
StringRef getKey() const {
|
||||
return StringRef(getKeyData(), getKeyLength());
|
||||
@@ -152,15 +156,14 @@ public:
|
||||
/// \p InitiVals.
|
||||
template <typename... InitTy>
|
||||
static StringMapEntry *Create(StringRef Key, InitTy &&... InitVals) {
|
||||
unsigned KeyLength = Key.size();
|
||||
size_t 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;
|
||||
size_t AllocSize = sizeof(StringMapEntry) + KeyLength + 1;
|
||||
|
||||
StringMapEntry *NewItem =
|
||||
static_cast<StringMapEntry*>(std::malloc(AllocSize));
|
||||
static_cast<StringMapEntry*>(CheckedMalloc(AllocSize));
|
||||
|
||||
// Construct the value.
|
||||
new (NewItem) StringMapEntry(KeyLength, std::forward<InitTy>(InitVals)...);
|
||||
@@ -201,9 +204,10 @@ public:
|
||||
template<typename ValueTy>
|
||||
class StringMap : public StringMapImpl {
|
||||
public:
|
||||
typedef StringMapEntry<ValueTy> MapEntryTy;
|
||||
using MapEntryTy = StringMapEntry<ValueTy>;
|
||||
|
||||
StringMap() : StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))) {}
|
||||
|
||||
explicit StringMap(unsigned InitialSize)
|
||||
: StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))) {}
|
||||
|
||||
@@ -217,11 +221,6 @@ public:
|
||||
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())
|
||||
@@ -256,14 +255,33 @@ public:
|
||||
// not worthwhile.
|
||||
}
|
||||
|
||||
StringMap &operator=(StringMap RHS) {
|
||||
StringMapImpl::swap(RHS);
|
||||
return *this;
|
||||
}
|
||||
|
||||
typedef const char* key_type;
|
||||
typedef ValueTy mapped_type;
|
||||
typedef StringMapEntry<ValueTy> value_type;
|
||||
typedef size_t size_type;
|
||||
~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);
|
||||
}
|
||||
|
||||
typedef StringMapConstIterator<ValueTy> const_iterator;
|
||||
typedef StringMapIterator<ValueTy> iterator;
|
||||
using key_type = const char*;
|
||||
using mapped_type = ValueTy;
|
||||
using value_type = StringMapEntry<ValueTy>;
|
||||
using size_type = size_t;
|
||||
|
||||
using const_iterator = StringMapConstIterator<ValueTy>;
|
||||
using iterator = StringMapIterator<ValueTy>;
|
||||
|
||||
iterator begin() {
|
||||
return iterator(TheTable, NumBuckets == 0);
|
||||
@@ -278,6 +296,11 @@ public:
|
||||
return const_iterator(TheTable+NumBuckets, true);
|
||||
}
|
||||
|
||||
iterator_range<StringMapKeyIterator<ValueTy>> keys() const {
|
||||
return make_range(StringMapKeyIterator<ValueTy>(begin()),
|
||||
StringMapKeyIterator<ValueTy>(end()));
|
||||
}
|
||||
|
||||
iterator find(StringRef Key) {
|
||||
int Bucket = FindKey(Key);
|
||||
if (Bucket == -1) return end();
|
||||
@@ -301,9 +324,7 @@ public:
|
||||
|
||||
/// 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;
|
||||
}
|
||||
ValueTy &operator[](StringRef Key) { return try_emplace(Key).first->second; }
|
||||
|
||||
/// count - Return 1 if the element is in the map, 0 otherwise.
|
||||
size_type count(StringRef Key) const {
|
||||
@@ -334,7 +355,13 @@ public:
|
||||
/// 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));
|
||||
return try_emplace(KV.first, std::move(KV.second));
|
||||
}
|
||||
|
||||
template <typename... ArgsTy>
|
||||
WPI_DEPRECATED("use try_emplace instead")
|
||||
std::pair<iterator, bool> emplace_second(StringRef Key, ArgsTy &&... Args) {
|
||||
return try_emplace(Key, std::forward<ArgsTy>(Args)...);
|
||||
}
|
||||
|
||||
/// Emplace a new element for the specified key into the map if the key isn't
|
||||
@@ -342,7 +369,7 @@ public:
|
||||
/// 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) {
|
||||
std::pair<iterator, bool> try_emplace(StringRef Key, ArgsTy &&... Args) {
|
||||
unsigned BucketNo = LookupBucketFor(Key);
|
||||
StringMapEntryBase *&Bucket = TheTable[BucketNo];
|
||||
if (Bucket && Bucket != getTombstoneVal())
|
||||
@@ -395,68 +422,53 @@ public:
|
||||
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 {
|
||||
template <typename DerivedTy, typename ValueTy>
|
||||
class StringMapIterBase
|
||||
: public iterator_facade_base<DerivedTy, std::forward_iterator_tag,
|
||||
ValueTy> {
|
||||
protected:
|
||||
StringMapEntryBase **Ptr;
|
||||
StringMapEntryBase **Ptr = nullptr;
|
||||
|
||||
public:
|
||||
typedef StringMapEntry<ValueTy> value_type;
|
||||
StringMapIterBase() = default;
|
||||
|
||||
StringMapConstIterator() : Ptr(nullptr) { }
|
||||
|
||||
explicit StringMapConstIterator(StringMapEntryBase **Bucket,
|
||||
bool NoAdvance = false)
|
||||
: Ptr(Bucket) {
|
||||
explicit StringMapIterBase(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);
|
||||
DerivedTy &operator=(const DerivedTy &Other) {
|
||||
Ptr = Other.Ptr;
|
||||
return static_cast<DerivedTy &>(*this);
|
||||
}
|
||||
|
||||
bool operator==(const StringMapConstIterator &RHS) const {
|
||||
return Ptr == RHS.Ptr;
|
||||
}
|
||||
bool operator!=(const StringMapConstIterator &RHS) const {
|
||||
return Ptr != RHS.Ptr;
|
||||
}
|
||||
bool operator==(const DerivedTy &RHS) const { return Ptr == RHS.Ptr; }
|
||||
|
||||
inline StringMapConstIterator& operator++() { // Preincrement
|
||||
DerivedTy &operator++() { // Preincrement
|
||||
++Ptr;
|
||||
AdvancePastEmptyBuckets();
|
||||
return *this;
|
||||
}
|
||||
StringMapConstIterator operator++(int) { // Postincrement
|
||||
StringMapConstIterator tmp = *this; ++*this; return tmp;
|
||||
return static_cast<DerivedTy &>(*this);
|
||||
}
|
||||
|
||||
inline StringMapConstIterator& operator--() { // Predecrement
|
||||
DerivedTy operator++(int) { // Post-increment
|
||||
DerivedTy Tmp(Ptr);
|
||||
++*this;
|
||||
return Tmp;
|
||||
}
|
||||
|
||||
DerivedTy &operator--() { // Predecrement
|
||||
--Ptr;
|
||||
ReversePastEmptyBuckets();
|
||||
return *this;
|
||||
return static_cast<DerivedTy &>(*this);
|
||||
}
|
||||
StringMapConstIterator operator--(int) { // Postdecrement
|
||||
StringMapConstIterator tmp = *this; --*this; return tmp;
|
||||
|
||||
DerivedTy operator--(int) { // Post-decrement
|
||||
DerivedTy Tmp(Ptr);
|
||||
--*this;
|
||||
return Tmp;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -470,20 +482,70 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ValueTy>
|
||||
class StringMapIterator : public StringMapConstIterator<ValueTy> {
|
||||
template <typename ValueTy>
|
||||
class StringMapConstIterator
|
||||
: public StringMapIterBase<StringMapConstIterator<ValueTy>,
|
||||
const StringMapEntry<ValueTy>> {
|
||||
using base = StringMapIterBase<StringMapConstIterator<ValueTy>,
|
||||
const StringMapEntry<ValueTy>>;
|
||||
|
||||
public:
|
||||
StringMapIterator() {}
|
||||
using value_type = const StringMapEntry<ValueTy>;
|
||||
|
||||
StringMapConstIterator() = default;
|
||||
explicit StringMapConstIterator(StringMapEntryBase **Bucket,
|
||||
bool NoAdvance = false)
|
||||
: base(Bucket, NoAdvance) {}
|
||||
|
||||
value_type &operator*() const {
|
||||
return *static_cast<value_type *>(*this->Ptr);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ValueTy>
|
||||
class StringMapIterator : public StringMapIterBase<StringMapIterator<ValueTy>,
|
||||
StringMapEntry<ValueTy>> {
|
||||
using base =
|
||||
StringMapIterBase<StringMapIterator<ValueTy>, StringMapEntry<ValueTy>>;
|
||||
|
||||
public:
|
||||
using value_type = StringMapEntry<ValueTy>;
|
||||
|
||||
StringMapIterator() = default;
|
||||
explicit StringMapIterator(StringMapEntryBase **Bucket,
|
||||
bool NoAdvance = false)
|
||||
: StringMapConstIterator<ValueTy>(Bucket, NoAdvance) {
|
||||
: base(Bucket, NoAdvance) {}
|
||||
|
||||
value_type &operator*() const {
|
||||
return *static_cast<value_type *>(*this->Ptr);
|
||||
}
|
||||
StringMapEntry<ValueTy> &operator*() const {
|
||||
return *static_cast<StringMapEntry<ValueTy>*>(*this->Ptr);
|
||||
|
||||
operator StringMapConstIterator<ValueTy>() const {
|
||||
return StringMapConstIterator<ValueTy>(this->Ptr, true);
|
||||
}
|
||||
StringMapEntry<ValueTy> *operator->() const {
|
||||
return static_cast<StringMapEntry<ValueTy>*>(*this->Ptr);
|
||||
};
|
||||
|
||||
template <typename ValueTy>
|
||||
class StringMapKeyIterator
|
||||
: public iterator_adaptor_base<StringMapKeyIterator<ValueTy>,
|
||||
StringMapConstIterator<ValueTy>,
|
||||
std::forward_iterator_tag, StringRef> {
|
||||
using base = iterator_adaptor_base<StringMapKeyIterator<ValueTy>,
|
||||
StringMapConstIterator<ValueTy>,
|
||||
std::forward_iterator_tag, StringRef>;
|
||||
|
||||
public:
|
||||
StringMapKeyIterator() = default;
|
||||
explicit StringMapKeyIterator(StringMapConstIterator<ValueTy> Iter)
|
||||
: base(std::move(Iter)) {}
|
||||
|
||||
StringRef &operator*() {
|
||||
Key = this->wrapped()->getKey();
|
||||
return Key;
|
||||
}
|
||||
|
||||
private:
|
||||
StringRef Key;
|
||||
};
|
||||
|
||||
template <typename ValueTy>
|
||||
@@ -571,6 +633,6 @@ inline bool operator>=(const StringMap<ValueTy>& lhs,
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
} // namespace wpi
|
||||
} // end namespace wpi
|
||||
|
||||
#endif
|
||||
#endif // LLVM_ADT_STRINGMAP_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//===--- StringRef.h - Constant String Reference Wrapper --------*- C++ -*-===//
|
||||
//===- StringRef.h - Constant String Reference Wrapper ----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@@ -7,23 +7,26 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_STRINGREF_H
|
||||
#define LLVM_ADT_STRINGREF_H
|
||||
#ifndef WPIUTIL_WPI_STRINGREF_H
|
||||
#define WPIUTIL_WPI_STRINGREF_H
|
||||
|
||||
#include "wpi/STLExtras.h"
|
||||
#include "wpi/iterator_range.h"
|
||||
#include "wpi/Compiler.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <iosfwd>
|
||||
#include <limits>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
template <typename T>
|
||||
class SmallVectorImpl;
|
||||
|
||||
class hash_code;
|
||||
template <typename T> class SmallVectorImpl;
|
||||
class StringRef;
|
||||
|
||||
/// Helper functions for StringRef::getAsInteger.
|
||||
@@ -32,6 +35,10 @@ namespace wpi {
|
||||
|
||||
bool getAsSignedInteger(StringRef Str, unsigned Radix, long long &Result) noexcept;
|
||||
|
||||
bool consumeUnsignedInteger(StringRef &Str, unsigned Radix,
|
||||
unsigned long long &Result) noexcept;
|
||||
bool consumeSignedInteger(StringRef &Str, unsigned Radix, long long &Result) noexcept;
|
||||
|
||||
/// StringRef - Represent a constant reference to a string, i.e. a character
|
||||
/// array and a length, which need not be null terminated.
|
||||
///
|
||||
@@ -41,76 +48,56 @@ namespace wpi {
|
||||
/// 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;
|
||||
|
||||
using iterator = const char *;
|
||||
using const_iterator = const char *;
|
||||
using size_type = size_t;
|
||||
|
||||
private:
|
||||
/// The start of the string, in an external buffer.
|
||||
const char *Data;
|
||||
const char *Data = nullptr;
|
||||
|
||||
/// 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;
|
||||
size_t Length = 0;
|
||||
|
||||
// Workaround memcmp issue with null pointers (undefined behavior)
|
||||
// by providing a specialized version
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
static int compareMemory(const char *Lhs, const char *Rhs, size_t Length) noexcept {
|
||||
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) noexcept {
|
||||
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() noexcept : Data(""), Length(0) {
|
||||
set_null_terminated(true);
|
||||
}
|
||||
/*implicit*/ StringRef() = default;
|
||||
|
||||
/// Disable conversion from nullptr. This prevents things like
|
||||
/// if (S == nullptr)
|
||||
StringRef(std::nullptr_t) = delete;
|
||||
|
||||
/// Construct a string ref from a cstring.
|
||||
/*implicit*/ StringRef(const char *Str) noexcept
|
||||
: 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);
|
||||
}
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
/*implicit*/ StringRef(const char *Str)
|
||||
: Data(Str), Length(Str ? ::strlen(Str) : 0) {}
|
||||
|
||||
/// Construct a string ref from a pointer and length.
|
||||
/*implicit*/ StringRef(const char *data, size_t length, bool isNullTerminated = false) noexcept
|
||||
: 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, use the parameter
|
||||
// Default to false (not null) to match previous behavior.
|
||||
set_null_terminated(isNullTerminated);
|
||||
}
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
/*implicit*/ constexpr StringRef(const char *data, size_t length)
|
||||
: Data(data), Length(length) {}
|
||||
|
||||
/// Construct a string ref from an std::string.
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
/*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);
|
||||
}
|
||||
: Data(Str.data()), Length(Str.length()) {}
|
||||
|
||||
static StringRef withNullAsEmpty(const char *data) {
|
||||
return StringRef(data ? data : "");
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Iterators
|
||||
@@ -118,7 +105,7 @@ namespace wpi {
|
||||
|
||||
iterator begin() const noexcept { return Data; }
|
||||
|
||||
iterator end() const noexcept { return Data + size(); }
|
||||
iterator end() const noexcept { return Data + Length; }
|
||||
|
||||
const unsigned char *bytes_begin() const noexcept {
|
||||
return reinterpret_cast<const unsigned char *>(begin());
|
||||
@@ -136,95 +123,110 @@ namespace wpi {
|
||||
|
||||
/// data - Get a pointer to the start of the string (which may not be null
|
||||
/// terminated).
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
const char *data() const noexcept { 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(wpi::SmallVectorImpl<char>& buf) const;
|
||||
|
||||
/// empty - Check if the string is empty.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
bool empty() const noexcept { return size() == 0; }
|
||||
|
||||
/// size - Get the string size.
|
||||
size_t size() const noexcept {
|
||||
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 noexcept {
|
||||
return (Length & ((size_t)1 << (sizeof(size_t) * 8 - 1))) ==
|
||||
((size_t)1 << (sizeof(size_t) * 8 - 1));
|
||||
}
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
size_t size() const noexcept { return Length; }
|
||||
|
||||
/// front - Get the first character in the string.
|
||||
LLVM_NODISCARD
|
||||
char front() const noexcept {
|
||||
assert(!empty());
|
||||
return Data[0];
|
||||
}
|
||||
|
||||
/// back - Get the last character in the string.
|
||||
LLVM_NODISCARD
|
||||
char back() const noexcept {
|
||||
assert(!empty());
|
||||
return Data[size()-1];
|
||||
return Data[Length-1];
|
||||
}
|
||||
|
||||
// copy - Allocate copy in Allocator and return StringRef to it.
|
||||
template <typename Allocator> StringRef copy(Allocator &A) const {
|
||||
template <typename Allocator>
|
||||
LLVM_NODISCARD 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());
|
||||
char *S = A.template Allocate<char>(Length);
|
||||
std::copy(begin(), end(), S);
|
||||
return StringRef(S, size());
|
||||
return StringRef(S, Length);
|
||||
}
|
||||
|
||||
/// equals - Check for string equality, this is more efficient than
|
||||
/// compare() when the relative ordering of inequal strings isn't needed.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
bool equals(StringRef RHS) const noexcept {
|
||||
return (size() == RHS.size() &&
|
||||
compareMemory(Data, RHS.Data, RHS.size()) == 0);
|
||||
return (Length == RHS.Length &&
|
||||
compareMemory(Data, RHS.Data, RHS.Length) == 0);
|
||||
}
|
||||
|
||||
/// equals_lower - Check for string equality, ignoring case.
|
||||
LLVM_NODISCARD
|
||||
bool equals_lower(StringRef RHS) const noexcept {
|
||||
return size() == RHS.size() && compare_lower(RHS) == 0;
|
||||
return Length == RHS.Length && 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.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
int compare(StringRef RHS) const noexcept {
|
||||
// Check the prefix for a mismatch.
|
||||
if (int Res = compareMemory(Data, RHS.Data, std::min(size(), RHS.size())))
|
||||
if (int Res = compareMemory(Data, RHS.Data, std::min(Length, RHS.Length)))
|
||||
return Res < 0 ? -1 : 1;
|
||||
|
||||
// Otherwise the prefixes match, so we only need to check the lengths.
|
||||
if (size() == RHS.size())
|
||||
if (Length == RHS.Length)
|
||||
return 0;
|
||||
return size() < RHS.size() ? -1 : 1;
|
||||
return Length < RHS.Length ? -1 : 1;
|
||||
}
|
||||
|
||||
/// compare_lower - Compare two strings, ignoring case.
|
||||
LLVM_NODISCARD
|
||||
int compare_lower(StringRef RHS) const noexcept;
|
||||
|
||||
/// compare_numeric - Compare two strings, treating sequences of digits as
|
||||
/// numbers.
|
||||
LLVM_NODISCARD
|
||||
int compare_numeric(StringRef RHS) const noexcept;
|
||||
|
||||
/// str - Get the contents as an std::string.
|
||||
LLVM_NODISCARD
|
||||
std::string str() const {
|
||||
if (!Data) return std::string();
|
||||
return std::string(Data, size());
|
||||
return std::string(Data, Length);
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Operator Overloads
|
||||
/// @{
|
||||
|
||||
LLVM_NODISCARD
|
||||
char operator[](size_t Index) const noexcept {
|
||||
assert(Index < size() && "Invalid index!");
|
||||
assert(Index < Length && "Invalid index!");
|
||||
return Data[Index];
|
||||
}
|
||||
|
||||
/// Disallow accidental assignment from a temporary std::string.
|
||||
///
|
||||
/// The declaration here is extra complicated so that `stringRef = {}`
|
||||
/// and `stringRef = "abc"` continue to select the move assignment operator.
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_same<T, std::string>::value,
|
||||
StringRef>::type &
|
||||
operator=(T &&Str) = delete;
|
||||
|
||||
/// @}
|
||||
/// @name Type Conversions
|
||||
/// @{
|
||||
@@ -238,21 +240,27 @@ namespace wpi {
|
||||
/// @{
|
||||
|
||||
/// Check if this string starts with the given \p Prefix.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
bool startswith(StringRef Prefix) const noexcept {
|
||||
return size() >= Prefix.size() &&
|
||||
compareMemory(Data, Prefix.Data, Prefix.size()) == 0;
|
||||
return Length >= Prefix.Length &&
|
||||
compareMemory(Data, Prefix.Data, Prefix.Length) == 0;
|
||||
}
|
||||
|
||||
/// Check if this string starts with the given \p Prefix, ignoring case.
|
||||
LLVM_NODISCARD
|
||||
bool startswith_lower(StringRef Prefix) const noexcept;
|
||||
|
||||
/// Check if this string ends with the given \p Suffix.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
bool endswith(StringRef Suffix) const noexcept {
|
||||
return size() >= Suffix.size() &&
|
||||
compareMemory(end() - Suffix.size(), Suffix.Data, Suffix.size()) == 0;
|
||||
return Length >= Suffix.Length &&
|
||||
compareMemory(end() - Suffix.Length, Suffix.Data, Suffix.Length) == 0;
|
||||
}
|
||||
|
||||
/// Check if this string ends with the given \p Suffix, ignoring case.
|
||||
LLVM_NODISCARD
|
||||
bool endswith_lower(StringRef Suffix) const noexcept;
|
||||
|
||||
/// @}
|
||||
@@ -263,28 +271,72 @@ namespace wpi {
|
||||
///
|
||||
/// \returns The index of the first occurrence of \p C, or npos if not
|
||||
/// found.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
size_t find(char C, size_t From = 0) const noexcept {
|
||||
size_t FindBegin = std::min(From, size());
|
||||
if (FindBegin < size()) { // Avoid calling memchr with nullptr.
|
||||
size_t FindBegin = std::min(From, Length);
|
||||
if (FindBegin < Length) { // 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))
|
||||
if (const void *P = ::memchr(Data + FindBegin, C, Length - FindBegin))
|
||||
return static_cast<const char *>(P) - Data;
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
/// Search for the first character \p C in the string, ignoring case.
|
||||
///
|
||||
/// \returns The index of the first occurrence of \p C, or npos if not
|
||||
/// found.
|
||||
LLVM_NODISCARD
|
||||
size_t find_lower(char C, size_t From = 0) const noexcept;
|
||||
|
||||
/// Search for the first character satisfying the predicate \p F
|
||||
///
|
||||
/// \returns The index of the first character satisfying \p F starting from
|
||||
/// \p From, or npos if not found.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
size_t find_if(function_ref<bool(char)> F, size_t From = 0) const noexcept {
|
||||
StringRef S = drop_front(From);
|
||||
while (!S.empty()) {
|
||||
if (F(S.front()))
|
||||
return size() - S.size();
|
||||
S = S.drop_front();
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
/// Search for the first character not satisfying the predicate \p F
|
||||
///
|
||||
/// \returns The index of the first character not satisfying \p F starting
|
||||
/// from \p From, or npos if not found.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
size_t find_if_not(function_ref<bool(char)> F, size_t From = 0) const noexcept {
|
||||
return find_if([F](char c) { return !F(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.
|
||||
LLVM_NODISCARD
|
||||
size_t find(StringRef Str, size_t From = 0) const noexcept;
|
||||
|
||||
/// Search for the first string \p Str in the string, ignoring case.
|
||||
///
|
||||
/// \returns The index of the first occurrence of \p Str, or npos if not
|
||||
/// found.
|
||||
LLVM_NODISCARD
|
||||
size_t find_lower(StringRef Str, size_t From = 0) const noexcept;
|
||||
|
||||
/// 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.
|
||||
LLVM_NODISCARD
|
||||
size_t rfind(char C, size_t From = npos) const noexcept {
|
||||
From = std::min(From, size());
|
||||
From = std::min(From, Length);
|
||||
size_t i = From;
|
||||
while (i != 0) {
|
||||
--i;
|
||||
@@ -294,14 +346,30 @@ namespace wpi {
|
||||
return npos;
|
||||
}
|
||||
|
||||
/// Search for the last character \p C in the string, ignoring case.
|
||||
///
|
||||
/// \returns The index of the last occurrence of \p C, or npos if not
|
||||
/// found.
|
||||
LLVM_NODISCARD
|
||||
size_t rfind_lower(char C, size_t From = npos) const noexcept;
|
||||
|
||||
/// 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.
|
||||
LLVM_NODISCARD
|
||||
size_t rfind(StringRef Str) const noexcept;
|
||||
|
||||
/// Search for the last string \p Str in the string, ignoring case.
|
||||
///
|
||||
/// \returns The index of the last occurrence of \p Str, or npos if not
|
||||
/// found.
|
||||
LLVM_NODISCARD
|
||||
size_t rfind_lower(StringRef Str) const noexcept;
|
||||
|
||||
/// Find the first character in the string that is \p C, or npos if not
|
||||
/// found. Same as find.
|
||||
LLVM_NODISCARD
|
||||
size_t find_first_of(char C, size_t From = 0) const noexcept {
|
||||
return find(C, From);
|
||||
}
|
||||
@@ -310,20 +378,24 @@ namespace wpi {
|
||||
/// not found.
|
||||
///
|
||||
/// Complexity: O(size() + Chars.size())
|
||||
LLVM_NODISCARD
|
||||
size_t find_first_of(StringRef Chars, size_t From = 0) const noexcept;
|
||||
|
||||
/// Find the first character in the string that is not \p C or npos if not
|
||||
/// found.
|
||||
LLVM_NODISCARD
|
||||
size_t find_first_not_of(char C, size_t From = 0) const noexcept;
|
||||
|
||||
/// 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())
|
||||
LLVM_NODISCARD
|
||||
size_t find_first_not_of(StringRef Chars, size_t From = 0) const noexcept;
|
||||
|
||||
/// Find the last character in the string that is \p C, or npos if not
|
||||
/// found.
|
||||
LLVM_NODISCARD
|
||||
size_t find_last_of(char C, size_t From = npos) const noexcept {
|
||||
return rfind(C, From);
|
||||
}
|
||||
@@ -332,26 +404,56 @@ namespace wpi {
|
||||
/// found.
|
||||
///
|
||||
/// Complexity: O(size() + Chars.size())
|
||||
LLVM_NODISCARD
|
||||
size_t find_last_of(StringRef Chars, size_t From = npos) const noexcept;
|
||||
|
||||
/// Find the last character in the string that is not \p C, or npos if not
|
||||
/// found.
|
||||
LLVM_NODISCARD
|
||||
size_t find_last_not_of(char C, size_t From = npos) const noexcept;
|
||||
|
||||
/// Find the last character in the string that is not in \p Chars, or
|
||||
/// npos if not found.
|
||||
///
|
||||
/// Complexity: O(size() + Chars.size())
|
||||
LLVM_NODISCARD
|
||||
size_t find_last_not_of(StringRef Chars, size_t From = npos) const noexcept;
|
||||
|
||||
/// Return true if the given string is a substring of *this, and false
|
||||
/// otherwise.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
bool contains(StringRef Other) const noexcept { return find(Other) != npos; }
|
||||
|
||||
/// Return true if the given character is contained in *this, and false
|
||||
/// otherwise.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
bool contains(char C) const noexcept { return find_first_of(C) != npos; }
|
||||
|
||||
/// Return true if the given string is a substring of *this, and false
|
||||
/// otherwise.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
bool contains_lower(StringRef Other) const noexcept {
|
||||
return find_lower(Other) != npos;
|
||||
}
|
||||
|
||||
/// Return true if the given character is contained in *this, and false
|
||||
/// otherwise.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
bool contains_lower(char C) const noexcept { return find_lower(C) != npos; }
|
||||
|
||||
/// @}
|
||||
/// @name Helpful Algorithms
|
||||
/// @{
|
||||
|
||||
/// Return the number of occurrences of \p C in the string.
|
||||
LLVM_NODISCARD
|
||||
size_t count(char C) const noexcept {
|
||||
size_t Count = 0;
|
||||
for (size_t i = 0, e = size(); i != e; ++i)
|
||||
for (size_t i = 0, e = Length; i != e; ++i)
|
||||
if (Data[i] == C)
|
||||
++Count;
|
||||
return Count;
|
||||
@@ -393,14 +495,47 @@ namespace wpi {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// 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 does not begin with a number of the specified radix,
|
||||
/// this returns true to signify the error. The string is considered
|
||||
/// erroneous if empty or if it overflows T.
|
||||
/// The portion of the string representing the discovered numeric value
|
||||
/// is removed from the beginning of the string.
|
||||
template <typename T>
|
||||
typename std::enable_if<std::numeric_limits<T>::is_signed, bool>::type
|
||||
consumeInteger(unsigned Radix, T &Result) noexcept {
|
||||
long long LLVal;
|
||||
if (consumeSignedInteger(*this, Radix, LLVal) ||
|
||||
static_cast<long long>(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
|
||||
consumeInteger(unsigned Radix, T &Result) noexcept {
|
||||
unsigned long long ULLVal;
|
||||
if (consumeUnsignedInteger(*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.
|
||||
LLVM_NODISCARD
|
||||
std::string lower() const;
|
||||
|
||||
/// Convert the given ASCII string to uppercase.
|
||||
LLVM_NODISCARD
|
||||
std::string upper() const;
|
||||
|
||||
/// @}
|
||||
@@ -416,13 +551,55 @@ namespace wpi {
|
||||
/// \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.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringRef substr(size_t Start, size_t N = npos) const noexcept {
|
||||
Start = std::min(Start, size());
|
||||
return StringRef(Data + Start, std::min(N, size() - Start));
|
||||
Start = std::min(Start, Length);
|
||||
return StringRef(Data + Start, std::min(N, Length - Start));
|
||||
}
|
||||
|
||||
/// Return a StringRef equal to 'this' but with only the first \p N
|
||||
/// elements remaining. If \p N is greater than the length of the
|
||||
/// string, the entire string is returned.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringRef take_front(size_t N = 1) const noexcept {
|
||||
if (N >= size())
|
||||
return *this;
|
||||
return drop_back(size() - N);
|
||||
}
|
||||
|
||||
/// Return a StringRef equal to 'this' but with only the last \p N
|
||||
/// elements remaining. If \p N is greater than the length of the
|
||||
/// string, the entire string is returned.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringRef take_back(size_t N = 1) const noexcept {
|
||||
if (N >= size())
|
||||
return *this;
|
||||
return drop_front(size() - N);
|
||||
}
|
||||
|
||||
/// Return the longest prefix of 'this' such that every character
|
||||
/// in the prefix satisfies the given predicate.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringRef take_while(function_ref<bool(char)> F) const noexcept {
|
||||
return substr(0, find_if_not(F));
|
||||
}
|
||||
|
||||
/// Return the longest prefix of 'this' such that no character in
|
||||
/// the prefix satisfies the given predicate.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringRef take_until(function_ref<bool(char)> F) const noexcept {
|
||||
return substr(0, find_if(F));
|
||||
}
|
||||
|
||||
/// Return a StringRef equal to 'this' but with the first \p N elements
|
||||
/// dropped.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringRef drop_front(size_t N = 1) const noexcept {
|
||||
assert(size() >= N && "Dropping more elements than exist");
|
||||
return substr(N);
|
||||
@@ -430,11 +607,51 @@ namespace wpi {
|
||||
|
||||
/// Return a StringRef equal to 'this' but with the last \p N elements
|
||||
/// dropped.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringRef drop_back(size_t N = 1) const noexcept {
|
||||
assert(size() >= N && "Dropping more elements than exist");
|
||||
return substr(0, size()-N);
|
||||
}
|
||||
|
||||
/// Return a StringRef equal to 'this', but with all characters satisfying
|
||||
/// the given predicate dropped from the beginning of the string.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringRef drop_while(function_ref<bool(char)> F) const noexcept {
|
||||
return substr(find_if_not(F));
|
||||
}
|
||||
|
||||
/// Return a StringRef equal to 'this', but with all characters not
|
||||
/// satisfying the given predicate dropped from the beginning of the string.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringRef drop_until(function_ref<bool(char)> F) const noexcept {
|
||||
return substr(find_if(F));
|
||||
}
|
||||
|
||||
/// Returns true if this StringRef has the given prefix and removes that
|
||||
/// prefix.
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
bool consume_front(StringRef Prefix) noexcept {
|
||||
if (!startswith(Prefix))
|
||||
return false;
|
||||
|
||||
*this = drop_front(Prefix.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Returns true if this StringRef has the given suffix and removes that
|
||||
/// suffix.
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
bool consume_back(StringRef Suffix) noexcept {
|
||||
if (!endswith(Suffix))
|
||||
return false;
|
||||
|
||||
*this = drop_back(Suffix.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Return a reference to the substring from [Start, End).
|
||||
///
|
||||
/// \param Start The index of the starting character in the substring; if
|
||||
@@ -446,9 +663,11 @@ namespace wpi {
|
||||
/// 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.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringRef slice(size_t Start, size_t End) const noexcept {
|
||||
Start = std::min(Start, size());
|
||||
End = std::min(std::max(Start, End), size());
|
||||
Start = std::min(Start, Length);
|
||||
End = std::min(std::max(Start, End), Length);
|
||||
return StringRef(Data + Start, End - Start);
|
||||
}
|
||||
|
||||
@@ -462,6 +681,7 @@ namespace wpi {
|
||||
///
|
||||
/// \param Separator The character to split on.
|
||||
/// \returns The split substrings.
|
||||
LLVM_NODISCARD
|
||||
std::pair<StringRef, StringRef> split(char Separator) const {
|
||||
size_t Idx = find(Separator);
|
||||
if (Idx == npos)
|
||||
@@ -479,6 +699,7 @@ namespace wpi {
|
||||
///
|
||||
/// \param Separator - The string to split on.
|
||||
/// \return - The split substrings.
|
||||
LLVM_NODISCARD
|
||||
std::pair<StringRef, StringRef> split(StringRef Separator) const {
|
||||
size_t Idx = find(Separator);
|
||||
if (Idx == npos)
|
||||
@@ -531,6 +752,7 @@ namespace wpi {
|
||||
///
|
||||
/// \param Separator - The character to split on.
|
||||
/// \return - The split substrings.
|
||||
LLVM_NODISCARD
|
||||
std::pair<StringRef, StringRef> rsplit(char Separator) const {
|
||||
size_t Idx = rfind(Separator);
|
||||
if (Idx == npos)
|
||||
@@ -540,36 +762,42 @@ namespace wpi {
|
||||
|
||||
/// Return string with consecutive \p Char characters starting from the
|
||||
/// the left removed.
|
||||
LLVM_NODISCARD
|
||||
StringRef ltrim(char Char) const noexcept {
|
||||
return drop_front(std::min(size(), find_first_not_of(Char)));
|
||||
return drop_front(std::min(Length, find_first_not_of(Char)));
|
||||
}
|
||||
|
||||
/// Return string with consecutive characters in \p Chars starting from
|
||||
/// the left removed.
|
||||
LLVM_NODISCARD
|
||||
StringRef ltrim(StringRef Chars = " \t\n\v\f\r") const noexcept {
|
||||
return drop_front(std::min(size(), find_first_not_of(Chars)));
|
||||
return drop_front(std::min(Length, find_first_not_of(Chars)));
|
||||
}
|
||||
|
||||
/// Return string with consecutive \p Char characters starting from the
|
||||
/// right removed.
|
||||
LLVM_NODISCARD
|
||||
StringRef rtrim(char Char) const noexcept {
|
||||
return drop_back(size() - std::min(size(), find_last_not_of(Char) + 1));
|
||||
return drop_back(size() - std::min(Length, find_last_not_of(Char) + 1));
|
||||
}
|
||||
|
||||
/// Return string with consecutive characters in \p Chars starting from
|
||||
/// the right removed.
|
||||
LLVM_NODISCARD
|
||||
StringRef rtrim(StringRef Chars = " \t\n\v\f\r") const noexcept {
|
||||
return drop_back(size() - std::min(size(), find_last_not_of(Chars) + 1));
|
||||
return drop_back(size() - std::min(Length, find_last_not_of(Chars) + 1));
|
||||
}
|
||||
|
||||
/// Return string with consecutive \p Char characters starting from the
|
||||
/// left and right removed.
|
||||
LLVM_NODISCARD
|
||||
StringRef trim(char Char) const noexcept {
|
||||
return ltrim(Char).rtrim(Char);
|
||||
}
|
||||
|
||||
/// Return string with consecutive characters in \p Chars starting from
|
||||
/// the left and right removed.
|
||||
LLVM_NODISCARD
|
||||
StringRef trim(StringRef Chars = " \t\n\v\f\r") const noexcept {
|
||||
return ltrim(Chars).rtrim(Chars);
|
||||
}
|
||||
@@ -577,14 +805,48 @@ namespace wpi {
|
||||
/// @}
|
||||
};
|
||||
|
||||
/// A wrapper around a string literal that serves as a proxy for constructing
|
||||
/// global tables of StringRefs with the length computed at compile time.
|
||||
/// In order to avoid the invocation of a global constructor, StringLiteral
|
||||
/// should *only* be used in a constexpr context, as such:
|
||||
///
|
||||
/// constexpr StringLiteral S("test");
|
||||
///
|
||||
class StringLiteral : public StringRef {
|
||||
private:
|
||||
constexpr StringLiteral(const char *Str, size_t N) : StringRef(Str, N) {
|
||||
}
|
||||
|
||||
public:
|
||||
template <size_t N>
|
||||
constexpr StringLiteral(const char (&Str)[N])
|
||||
#if defined(__clang__) && __has_attribute(enable_if)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wgcc-compat"
|
||||
__attribute((enable_if(__builtin_strlen(Str) == N - 1,
|
||||
"invalid string literal")))
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
: StringRef(Str, N - 1) {
|
||||
}
|
||||
|
||||
// Explicit construction for strings like "foo\0bar".
|
||||
template <size_t N>
|
||||
static constexpr StringLiteral withInnerNUL(const char (&Str)[N]) {
|
||||
return StringLiteral(Str, N - 1);
|
||||
}
|
||||
};
|
||||
|
||||
/// @name StringRef Comparison Operators
|
||||
/// @{
|
||||
|
||||
inline bool operator==(StringRef LHS, StringRef RHS) noexcept {
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
bool operator==(StringRef LHS, StringRef RHS) noexcept {
|
||||
return LHS.equals(RHS);
|
||||
}
|
||||
|
||||
inline bool operator!=(StringRef LHS, StringRef RHS) noexcept {
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
bool operator!=(StringRef LHS, StringRef RHS) noexcept {
|
||||
return !(LHS == RHS);
|
||||
}
|
||||
|
||||
@@ -656,19 +918,18 @@ namespace wpi {
|
||||
return buffer.append(string.data(), string.size());
|
||||
}
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &os, StringRef string) {
|
||||
os.write(string.data(), string.size());
|
||||
return os;
|
||||
}
|
||||
std::ostream &operator<<(std::ostream &os, StringRef string);
|
||||
|
||||
/// @}
|
||||
|
||||
/// \brief Compute a hash_code for a StringRef.
|
||||
/// Compute a hash_code for a StringRef.
|
||||
LLVM_NODISCARD
|
||||
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 wpi
|
||||
|
||||
#endif
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // LLVM_ADT_STRINGREF_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//===-- Twine.h - Fast Temporary String Concatenation -----------*- C++ -*-===//
|
||||
//===- Twine.h - Fast Temporary String Concatenation ------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@@ -7,17 +7,17 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_TWINE_H
|
||||
#define LLVM_ADT_TWINE_H
|
||||
#ifndef WPIUTIL_WPI_TWINE_H
|
||||
#define WPIUTIL_WPI_TWINE_H
|
||||
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/StringRef.h"
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
class raw_ostream;
|
||||
|
||||
/// Twine - A lightweight data structure for efficiently representing the
|
||||
@@ -146,22 +146,22 @@ namespace wpi {
|
||||
const uint64_t *uHex;
|
||||
};
|
||||
|
||||
private:
|
||||
/// LHS - The prefix in the concatenation, which may be uninitialized for
|
||||
/// Null or Empty kinds.
|
||||
Child LHS;
|
||||
|
||||
/// RHS - The suffix in the concatenation, which may be uninitialized for
|
||||
/// Null or Empty kinds.
|
||||
Child RHS;
|
||||
/// LHSKind - The NodeKind of the left hand side, \see getLHSKind().
|
||||
NodeKind LHSKind;
|
||||
/// RHSKind - The NodeKind of the right hand side, \see getRHSKind().
|
||||
NodeKind RHSKind;
|
||||
|
||||
private:
|
||||
/// LHSKind - The NodeKind of the left hand side, \see getLHSKind().
|
||||
NodeKind LHSKind = EmptyKind;
|
||||
|
||||
/// RHSKind - The NodeKind of the right hand side, \see getRHSKind().
|
||||
NodeKind RHSKind = EmptyKind;
|
||||
|
||||
/// Construct a nullary twine; the kind must be NullKind or EmptyKind.
|
||||
explicit Twine(NodeKind Kind)
|
||||
: LHSKind(Kind), RHSKind(EmptyKind) {
|
||||
explicit Twine(NodeKind Kind) : LHSKind(Kind) {
|
||||
assert(isNullary() && "Invalid kind!");
|
||||
}
|
||||
|
||||
@@ -179,10 +179,6 @@ namespace wpi {
|
||||
assert(isValid() && "Invalid twine!");
|
||||
}
|
||||
|
||||
/// Since the intended use of twines is as temporary objects, assignments
|
||||
/// when concatenating might cause undefined behavior or stack corruptions
|
||||
Twine &operator=(const Twine &Other) = delete;
|
||||
|
||||
/// Check for the null twine.
|
||||
bool isNull() const {
|
||||
return getLHSKind() == NullKind;
|
||||
@@ -252,7 +248,7 @@ namespace wpi {
|
||||
/// @{
|
||||
|
||||
/// Construct from an empty string.
|
||||
/*implicit*/ Twine() : LHSKind(EmptyKind), RHSKind(EmptyKind) {
|
||||
/*implicit*/ Twine() {
|
||||
assert(isValid() && "Invalid twine!");
|
||||
}
|
||||
|
||||
@@ -263,8 +259,7 @@ namespace wpi {
|
||||
/// We take care here to optimize "" into the empty twine -- this will be
|
||||
/// optimized out for string constants. This allows Twine arguments have
|
||||
/// default "" values, without introducing unnecessary string constants.
|
||||
/*implicit*/ Twine(const char *Str)
|
||||
: RHSKind(EmptyKind) {
|
||||
/*implicit*/ Twine(const char *Str) {
|
||||
if (Str[0] != '\0') {
|
||||
LHS.cString = Str;
|
||||
LHSKind = CStringKind;
|
||||
@@ -275,77 +270,66 @@ namespace wpi {
|
||||
}
|
||||
|
||||
/// Construct from an std::string.
|
||||
/*implicit*/ Twine(const std::string &Str)
|
||||
: LHSKind(StdStringKind), RHSKind(EmptyKind) {
|
||||
/*implicit*/ Twine(const std::string &Str) : LHSKind(StdStringKind) {
|
||||
LHS.stdString = &Str;
|
||||
assert(isValid() && "Invalid twine!");
|
||||
}
|
||||
|
||||
/// Construct from a StringRef.
|
||||
/*implicit*/ Twine(const StringRef &Str)
|
||||
: LHSKind(StringRefKind), RHSKind(EmptyKind) {
|
||||
/*implicit*/ Twine(const StringRef &Str) : LHSKind(StringRefKind) {
|
||||
LHS.stringRef = &Str;
|
||||
assert(isValid() && "Invalid twine!");
|
||||
}
|
||||
|
||||
/// Construct from a SmallString.
|
||||
/*implicit*/ Twine(const SmallVectorImpl<char> &Str)
|
||||
: LHSKind(SmallStringKind), RHSKind(EmptyKind) {
|
||||
: LHSKind(SmallStringKind) {
|
||||
LHS.smallString = &Str;
|
||||
assert(isValid() && "Invalid twine!");
|
||||
}
|
||||
|
||||
/// Construct from a char.
|
||||
explicit Twine(char Val)
|
||||
: LHSKind(CharKind), RHSKind(EmptyKind) {
|
||||
explicit Twine(char Val) : LHSKind(CharKind) {
|
||||
LHS.character = Val;
|
||||
}
|
||||
|
||||
/// Construct from a signed char.
|
||||
explicit Twine(signed char Val)
|
||||
: LHSKind(CharKind), RHSKind(EmptyKind) {
|
||||
explicit Twine(signed char Val) : LHSKind(CharKind) {
|
||||
LHS.character = static_cast<char>(Val);
|
||||
}
|
||||
|
||||
/// Construct from an unsigned char.
|
||||
explicit Twine(unsigned char Val)
|
||||
: LHSKind(CharKind), RHSKind(EmptyKind) {
|
||||
explicit Twine(unsigned char Val) : LHSKind(CharKind) {
|
||||
LHS.character = static_cast<char>(Val);
|
||||
}
|
||||
|
||||
/// Construct a twine to print \p Val as an unsigned decimal integer.
|
||||
explicit Twine(unsigned Val)
|
||||
: LHSKind(DecUIKind), RHSKind(EmptyKind) {
|
||||
explicit Twine(unsigned Val) : LHSKind(DecUIKind) {
|
||||
LHS.decUI = Val;
|
||||
}
|
||||
|
||||
/// Construct a twine to print \p Val as a signed decimal integer.
|
||||
explicit Twine(int Val)
|
||||
: LHSKind(DecIKind), RHSKind(EmptyKind) {
|
||||
explicit Twine(int Val) : LHSKind(DecIKind) {
|
||||
LHS.decI = Val;
|
||||
}
|
||||
|
||||
/// Construct a twine to print \p Val as an unsigned decimal integer.
|
||||
explicit Twine(const unsigned long &Val)
|
||||
: LHSKind(DecULKind), RHSKind(EmptyKind) {
|
||||
explicit Twine(const unsigned long &Val) : LHSKind(DecULKind) {
|
||||
LHS.decUL = &Val;
|
||||
}
|
||||
|
||||
/// Construct a twine to print \p Val as a signed decimal integer.
|
||||
explicit Twine(const long &Val)
|
||||
: LHSKind(DecLKind), RHSKind(EmptyKind) {
|
||||
explicit Twine(const long &Val) : LHSKind(DecLKind) {
|
||||
LHS.decL = &Val;
|
||||
}
|
||||
|
||||
/// Construct a twine to print \p Val as an unsigned decimal integer.
|
||||
explicit Twine(const unsigned long long &Val)
|
||||
: LHSKind(DecULLKind), RHSKind(EmptyKind) {
|
||||
explicit Twine(const unsigned long long &Val) : LHSKind(DecULLKind) {
|
||||
LHS.decULL = &Val;
|
||||
}
|
||||
|
||||
/// Construct a twine to print \p Val as a signed decimal integer.
|
||||
explicit Twine(const long long &Val)
|
||||
: LHSKind(DecLLKind), RHSKind(EmptyKind) {
|
||||
explicit Twine(const long long &Val) : LHSKind(DecLLKind) {
|
||||
LHS.decLL = &Val;
|
||||
}
|
||||
|
||||
@@ -370,6 +354,10 @@ namespace wpi {
|
||||
assert(isValid() && "Invalid twine!");
|
||||
}
|
||||
|
||||
/// Since the intended use of twines is as temporary objects, assignments
|
||||
/// when concatenating might cause undefined behavior or stack corruptions
|
||||
Twine &operator=(const Twine &) = delete;
|
||||
|
||||
/// Create a 'null' string, which is an empty string that always
|
||||
/// concatenates to form another empty string.
|
||||
static Twine createNull() {
|
||||
@@ -539,6 +527,7 @@ namespace wpi {
|
||||
}
|
||||
|
||||
/// @}
|
||||
}
|
||||
|
||||
#endif
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // LLVM_ADT_TWINE_H
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "wpi/ArrayRef.h"
|
||||
#include "wpi/StringRef.h"
|
||||
#include "wpi/Twine.h"
|
||||
#include "wpi/mutex.h"
|
||||
|
||||
namespace wpi {
|
||||
@@ -25,7 +26,7 @@ class UDPClient {
|
||||
|
||||
public:
|
||||
explicit UDPClient(Logger& logger);
|
||||
UDPClient(StringRef address, Logger& logger);
|
||||
UDPClient(const Twine& address, Logger& logger);
|
||||
UDPClient(const UDPClient& other) = delete;
|
||||
UDPClient(UDPClient&& other);
|
||||
~UDPClient();
|
||||
@@ -36,8 +37,8 @@ class UDPClient {
|
||||
int start();
|
||||
void shutdown();
|
||||
// The passed in address MUST be a resolved IP address.
|
||||
int send(ArrayRef<uint8_t> data, StringRef server, int port);
|
||||
int send(StringRef data, StringRef server, int port);
|
||||
int send(ArrayRef<uint8_t> data, const Twine& server, int port);
|
||||
int send(StringRef data, const Twine& server, int port);
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_WINDOWSERROR_H
|
||||
#define LLVM_SUPPORT_WINDOWSERROR_H
|
||||
#ifndef WPIUTIL_WPI_WINDOWSERROR_H
|
||||
#define WPIUTIL_WPI_WINDOWSERROR_H
|
||||
|
||||
#include <system_error>
|
||||
|
||||
|
||||
339
wpiutil/src/main/native/include/wpi/iterator.h
Normal file
339
wpiutil/src/main/native/include/wpi/iterator.h
Normal file
@@ -0,0 +1,339 @@
|
||||
//===- iterator.h - Utilities for using and defining iterators --*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_ITERATOR_H
|
||||
#define WPIUTIL_WPI_ITERATOR_H
|
||||
|
||||
#include "wpi/iterator_range.h"
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// CRTP base class which implements the entire standard iterator facade
|
||||
/// in terms of a minimal subset of the interface.
|
||||
///
|
||||
/// Use this when it is reasonable to implement most of the iterator
|
||||
/// functionality in terms of a core subset. If you need special behavior or
|
||||
/// there are performance implications for this, you may want to override the
|
||||
/// relevant members instead.
|
||||
///
|
||||
/// Note, one abstraction that this does *not* provide is implementing
|
||||
/// subtraction in terms of addition by negating the difference. Negation isn't
|
||||
/// always information preserving, and I can see very reasonable iterator
|
||||
/// designs where this doesn't work well. It doesn't really force much added
|
||||
/// boilerplate anyways.
|
||||
///
|
||||
/// Another abstraction that this doesn't provide is implementing increment in
|
||||
/// terms of addition of one. These aren't equivalent for all iterator
|
||||
/// categories, and respecting that adds a lot of complexity for little gain.
|
||||
///
|
||||
/// Classes wishing to use `iterator_facade_base` should implement the following
|
||||
/// methods:
|
||||
///
|
||||
/// Forward Iterators:
|
||||
/// (All of the following methods)
|
||||
/// - DerivedT &operator=(const DerivedT &R);
|
||||
/// - bool operator==(const DerivedT &R) const;
|
||||
/// - const T &operator*() const;
|
||||
/// - T &operator*();
|
||||
/// - DerivedT &operator++();
|
||||
///
|
||||
/// Bidirectional Iterators:
|
||||
/// (All methods of forward iterators, plus the following)
|
||||
/// - DerivedT &operator--();
|
||||
///
|
||||
/// Random-access Iterators:
|
||||
/// (All methods of bidirectional iterators excluding the following)
|
||||
/// - DerivedT &operator++();
|
||||
/// - DerivedT &operator--();
|
||||
/// (and plus the following)
|
||||
/// - bool operator<(const DerivedT &RHS) const;
|
||||
/// - DifferenceTypeT operator-(const DerivedT &R) const;
|
||||
/// - DerivedT &operator+=(DifferenceTypeT N);
|
||||
/// - DerivedT &operator-=(DifferenceTypeT N);
|
||||
///
|
||||
template <typename DerivedT, typename IteratorCategoryT, typename T,
|
||||
typename DifferenceTypeT = std::ptrdiff_t, typename PointerT = T *,
|
||||
typename ReferenceT = T &>
|
||||
class iterator_facade_base
|
||||
: public std::iterator<IteratorCategoryT, T, DifferenceTypeT, PointerT,
|
||||
ReferenceT> {
|
||||
protected:
|
||||
enum {
|
||||
IsRandomAccess = std::is_base_of<std::random_access_iterator_tag,
|
||||
IteratorCategoryT>::value,
|
||||
IsBidirectional = std::is_base_of<std::bidirectional_iterator_tag,
|
||||
IteratorCategoryT>::value,
|
||||
};
|
||||
|
||||
/// A proxy object for computing a reference via indirecting a copy of an
|
||||
/// iterator. This is used in APIs which need to produce a reference via
|
||||
/// indirection but for which the iterator object might be a temporary. The
|
||||
/// proxy preserves the iterator internally and exposes the indirected
|
||||
/// reference via a conversion operator.
|
||||
class ReferenceProxy {
|
||||
friend iterator_facade_base;
|
||||
|
||||
DerivedT I;
|
||||
|
||||
ReferenceProxy(DerivedT I) : I(std::move(I)) {}
|
||||
|
||||
public:
|
||||
operator ReferenceT() const { return *I; }
|
||||
};
|
||||
|
||||
public:
|
||||
DerivedT operator+(DifferenceTypeT n) const {
|
||||
static_assert(std::is_base_of<iterator_facade_base, DerivedT>::value,
|
||||
"Must pass the derived type to this template!");
|
||||
static_assert(
|
||||
IsRandomAccess,
|
||||
"The '+' operator is only defined for random access iterators.");
|
||||
DerivedT tmp = *static_cast<const DerivedT *>(this);
|
||||
tmp += n;
|
||||
return tmp;
|
||||
}
|
||||
friend DerivedT operator+(DifferenceTypeT n, const DerivedT &i) {
|
||||
static_assert(
|
||||
IsRandomAccess,
|
||||
"The '+' operator is only defined for random access iterators.");
|
||||
return i + n;
|
||||
}
|
||||
DerivedT operator-(DifferenceTypeT n) const {
|
||||
static_assert(
|
||||
IsRandomAccess,
|
||||
"The '-' operator is only defined for random access iterators.");
|
||||
DerivedT tmp = *static_cast<const DerivedT *>(this);
|
||||
tmp -= n;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
DerivedT &operator++() {
|
||||
static_assert(std::is_base_of<iterator_facade_base, DerivedT>::value,
|
||||
"Must pass the derived type to this template!");
|
||||
return static_cast<DerivedT *>(this)->operator+=(1);
|
||||
}
|
||||
DerivedT operator++(int) {
|
||||
DerivedT tmp = *static_cast<DerivedT *>(this);
|
||||
++*static_cast<DerivedT *>(this);
|
||||
return tmp;
|
||||
}
|
||||
DerivedT &operator--() {
|
||||
static_assert(
|
||||
IsBidirectional,
|
||||
"The decrement operator is only defined for bidirectional iterators.");
|
||||
return static_cast<DerivedT *>(this)->operator-=(1);
|
||||
}
|
||||
DerivedT operator--(int) {
|
||||
static_assert(
|
||||
IsBidirectional,
|
||||
"The decrement operator is only defined for bidirectional iterators.");
|
||||
DerivedT tmp = *static_cast<DerivedT *>(this);
|
||||
--*static_cast<DerivedT *>(this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator!=(const DerivedT &RHS) const {
|
||||
return !static_cast<const DerivedT *>(this)->operator==(RHS);
|
||||
}
|
||||
|
||||
bool operator>(const DerivedT &RHS) const {
|
||||
static_assert(
|
||||
IsRandomAccess,
|
||||
"Relational operators are only defined for random access iterators.");
|
||||
return !static_cast<const DerivedT *>(this)->operator<(RHS) &&
|
||||
!static_cast<const DerivedT *>(this)->operator==(RHS);
|
||||
}
|
||||
bool operator<=(const DerivedT &RHS) const {
|
||||
static_assert(
|
||||
IsRandomAccess,
|
||||
"Relational operators are only defined for random access iterators.");
|
||||
return !static_cast<const DerivedT *>(this)->operator>(RHS);
|
||||
}
|
||||
bool operator>=(const DerivedT &RHS) const {
|
||||
static_assert(
|
||||
IsRandomAccess,
|
||||
"Relational operators are only defined for random access iterators.");
|
||||
return !static_cast<const DerivedT *>(this)->operator<(RHS);
|
||||
}
|
||||
|
||||
PointerT operator->() { return &static_cast<DerivedT *>(this)->operator*(); }
|
||||
PointerT operator->() const {
|
||||
return &static_cast<const DerivedT *>(this)->operator*();
|
||||
}
|
||||
ReferenceProxy operator[](DifferenceTypeT n) {
|
||||
static_assert(IsRandomAccess,
|
||||
"Subscripting is only defined for random access iterators.");
|
||||
return ReferenceProxy(static_cast<DerivedT *>(this)->operator+(n));
|
||||
}
|
||||
ReferenceProxy operator[](DifferenceTypeT n) const {
|
||||
static_assert(IsRandomAccess,
|
||||
"Subscripting is only defined for random access iterators.");
|
||||
return ReferenceProxy(static_cast<const DerivedT *>(this)->operator+(n));
|
||||
}
|
||||
};
|
||||
|
||||
/// CRTP base class for adapting an iterator to a different type.
|
||||
///
|
||||
/// This class can be used through CRTP to adapt one iterator into another.
|
||||
/// Typically this is done through providing in the derived class a custom \c
|
||||
/// operator* implementation. Other methods can be overridden as well.
|
||||
template <
|
||||
typename DerivedT, typename WrappedIteratorT,
|
||||
typename IteratorCategoryT =
|
||||
typename std::iterator_traits<WrappedIteratorT>::iterator_category,
|
||||
typename T = typename std::iterator_traits<WrappedIteratorT>::value_type,
|
||||
typename DifferenceTypeT =
|
||||
typename std::iterator_traits<WrappedIteratorT>::difference_type,
|
||||
typename PointerT = typename std::conditional<
|
||||
std::is_same<T, typename std::iterator_traits<
|
||||
WrappedIteratorT>::value_type>::value,
|
||||
typename std::iterator_traits<WrappedIteratorT>::pointer, T *>::type,
|
||||
typename ReferenceT = typename std::conditional<
|
||||
std::is_same<T, typename std::iterator_traits<
|
||||
WrappedIteratorT>::value_type>::value,
|
||||
typename std::iterator_traits<WrappedIteratorT>::reference, T &>::type,
|
||||
// Don't provide these, they are mostly to act as aliases below.
|
||||
typename WrappedTraitsT = std::iterator_traits<WrappedIteratorT>>
|
||||
class iterator_adaptor_base
|
||||
: public iterator_facade_base<DerivedT, IteratorCategoryT, T,
|
||||
DifferenceTypeT, PointerT, ReferenceT> {
|
||||
using BaseT = typename iterator_adaptor_base::iterator_facade_base;
|
||||
|
||||
protected:
|
||||
WrappedIteratorT I;
|
||||
|
||||
iterator_adaptor_base() = default;
|
||||
|
||||
explicit iterator_adaptor_base(WrappedIteratorT u) : I(std::move(u)) {
|
||||
static_assert(std::is_base_of<iterator_adaptor_base, DerivedT>::value,
|
||||
"Must pass the derived type to this template!");
|
||||
}
|
||||
|
||||
const WrappedIteratorT &wrapped() const { return I; }
|
||||
|
||||
public:
|
||||
using difference_type = DifferenceTypeT;
|
||||
|
||||
DerivedT &operator+=(difference_type n) {
|
||||
static_assert(
|
||||
BaseT::IsRandomAccess,
|
||||
"The '+=' operator is only defined for random access iterators.");
|
||||
I += n;
|
||||
return *static_cast<DerivedT *>(this);
|
||||
}
|
||||
DerivedT &operator-=(difference_type n) {
|
||||
static_assert(
|
||||
BaseT::IsRandomAccess,
|
||||
"The '-=' operator is only defined for random access iterators.");
|
||||
I -= n;
|
||||
return *static_cast<DerivedT *>(this);
|
||||
}
|
||||
using BaseT::operator-;
|
||||
difference_type operator-(const DerivedT &RHS) const {
|
||||
static_assert(
|
||||
BaseT::IsRandomAccess,
|
||||
"The '-' operator is only defined for random access iterators.");
|
||||
return I - RHS.I;
|
||||
}
|
||||
|
||||
// We have to explicitly provide ++ and -- rather than letting the facade
|
||||
// forward to += because WrappedIteratorT might not support +=.
|
||||
using BaseT::operator++;
|
||||
DerivedT &operator++() {
|
||||
++I;
|
||||
return *static_cast<DerivedT *>(this);
|
||||
}
|
||||
using BaseT::operator--;
|
||||
DerivedT &operator--() {
|
||||
static_assert(
|
||||
BaseT::IsBidirectional,
|
||||
"The decrement operator is only defined for bidirectional iterators.");
|
||||
--I;
|
||||
return *static_cast<DerivedT *>(this);
|
||||
}
|
||||
|
||||
bool operator==(const DerivedT &RHS) const { return I == RHS.I; }
|
||||
bool operator<(const DerivedT &RHS) const {
|
||||
static_assert(
|
||||
BaseT::IsRandomAccess,
|
||||
"Relational operators are only defined for random access iterators.");
|
||||
return I < RHS.I;
|
||||
}
|
||||
|
||||
ReferenceT operator*() const { return *I; }
|
||||
};
|
||||
|
||||
/// An iterator type that allows iterating over the pointees via some
|
||||
/// other iterator.
|
||||
///
|
||||
/// The typical usage of this is to expose a type that iterates over Ts, but
|
||||
/// which is implemented with some iterator over T*s:
|
||||
///
|
||||
/// \code
|
||||
/// using iterator = pointee_iterator<SmallVectorImpl<T *>::iterator>;
|
||||
/// \endcode
|
||||
template <typename WrappedIteratorT,
|
||||
typename T = typename std::remove_reference<
|
||||
decltype(**std::declval<WrappedIteratorT>())>::type>
|
||||
struct pointee_iterator
|
||||
: iterator_adaptor_base<
|
||||
pointee_iterator<WrappedIteratorT>, WrappedIteratorT,
|
||||
typename std::iterator_traits<WrappedIteratorT>::iterator_category,
|
||||
T> {
|
||||
pointee_iterator() = default;
|
||||
template <typename U>
|
||||
pointee_iterator(U &&u)
|
||||
: pointee_iterator::iterator_adaptor_base(std::forward<U &&>(u)) {}
|
||||
|
||||
T &operator*() const { return **this->I; }
|
||||
};
|
||||
|
||||
template <typename RangeT, typename WrappedIteratorT =
|
||||
decltype(std::begin(std::declval<RangeT>()))>
|
||||
iterator_range<pointee_iterator<WrappedIteratorT>>
|
||||
make_pointee_range(RangeT &&Range) {
|
||||
using PointeeIteratorT = pointee_iterator<WrappedIteratorT>;
|
||||
return make_range(PointeeIteratorT(std::begin(std::forward<RangeT>(Range))),
|
||||
PointeeIteratorT(std::end(std::forward<RangeT>(Range))));
|
||||
}
|
||||
|
||||
template <typename WrappedIteratorT,
|
||||
typename T = decltype(&*std::declval<WrappedIteratorT>())>
|
||||
class pointer_iterator
|
||||
: public iterator_adaptor_base<pointer_iterator<WrappedIteratorT>,
|
||||
WrappedIteratorT, T> {
|
||||
mutable T Ptr;
|
||||
|
||||
public:
|
||||
pointer_iterator() = default;
|
||||
|
||||
explicit pointer_iterator(WrappedIteratorT u)
|
||||
: pointer_iterator::iterator_adaptor_base(std::move(u)) {}
|
||||
|
||||
T &operator*() { return Ptr = &*this->I; }
|
||||
const T &operator*() const { return Ptr = &*this->I; }
|
||||
};
|
||||
|
||||
template <typename RangeT, typename WrappedIteratorT =
|
||||
decltype(std::begin(std::declval<RangeT>()))>
|
||||
iterator_range<pointer_iterator<WrappedIteratorT>>
|
||||
make_pointer_range(RangeT &&Range) {
|
||||
using PointerIteratorT = pointer_iterator<WrappedIteratorT>;
|
||||
return make_range(PointerIteratorT(std::begin(std::forward<RangeT>(Range))),
|
||||
PointerIteratorT(std::end(std::forward<RangeT>(Range))));
|
||||
}
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // LLVM_ADT_ITERATOR_H
|
||||
@@ -16,15 +16,15 @@
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_ITERATOR_RANGE_H
|
||||
#define LLVM_ADT_ITERATOR_RANGE_H
|
||||
#ifndef WPIUTIL_WPI_ITERATOR_RANGE_H
|
||||
#define WPIUTIL_WPI_ITERATOR_RANGE_H
|
||||
|
||||
#include <utility>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// \brief A range adaptor for a pair of iterators.
|
||||
/// A range adaptor for a pair of iterators.
|
||||
///
|
||||
/// This just wraps two iterators into a range-compatible interface. Nothing
|
||||
/// fancy at all.
|
||||
@@ -47,7 +47,7 @@ public:
|
||||
IteratorT end() const { return end_iterator; }
|
||||
};
|
||||
|
||||
/// \brief Convenience function for iterating over sub-ranges.
|
||||
/// 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().
|
||||
|
||||
@@ -952,7 +952,7 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::object_t& obj)
|
||||
|
||||
auto inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();
|
||||
for (const auto& i : *inner_object) {
|
||||
obj.emplace_second(i.first(), i.second);
|
||||
obj.try_emplace(i.first(), i.second);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1247,7 +1247,7 @@ struct external_constructor<value_t::object>
|
||||
j.m_value = value_t::object;
|
||||
for (const auto& x : obj)
|
||||
{
|
||||
j.m_value.object->emplace_second(x.first, x.second);
|
||||
j.m_value.object->try_emplace(x.first, x.second);
|
||||
}
|
||||
j.assert_invariant();
|
||||
}
|
||||
@@ -6188,7 +6188,7 @@ class json
|
||||
}
|
||||
|
||||
// add element to array
|
||||
m_value.object->emplace_second(val.first, std::move(val.second));
|
||||
m_value.object->try_emplace(val.first, std::move(val.second));
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -6326,7 +6326,7 @@ class json
|
||||
}
|
||||
|
||||
// add element to array (perfect forwarding)
|
||||
auto res = m_value.object->emplace_second(key, std::forward<Args>(args)...);
|
||||
auto res = m_value.object->try_emplace(key, std::forward<Args>(args)...);
|
||||
// create result iterator and set iterator to the result of emplace
|
||||
auto it = begin();
|
||||
it.m_it.object_iterator = res.first;
|
||||
|
||||
@@ -9,9 +9,6 @@
|
||||
#define WPIUTIL_WPI_MEMORY_H_
|
||||
|
||||
#include <cstdlib>
|
||||
#include <exception>
|
||||
|
||||
#include "wpi/raw_ostream.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
@@ -21,28 +18,14 @@ namespace wpi {
|
||||
* @param size number of bytes per object to allocate
|
||||
* @return Pointer to beginning of newly allocated memory.
|
||||
*/
|
||||
inline void* CheckedCalloc(size_t num, size_t size) {
|
||||
void* p = std::calloc(num, size);
|
||||
if (!p) {
|
||||
errs() << "FATAL: failed to allocate " << (num * size) << " bytes\n";
|
||||
std::terminate();
|
||||
}
|
||||
return p;
|
||||
}
|
||||
void* CheckedCalloc(size_t num, size_t size);
|
||||
|
||||
/**
|
||||
* Wrapper around std::malloc that calls std::terminate on out of memory.
|
||||
* @param size number of bytes to allocate
|
||||
* @return Pointer to beginning of newly allocated memory.
|
||||
*/
|
||||
inline void* CheckedMalloc(size_t size) {
|
||||
void* p = std::malloc(size == 0 ? 1 : size);
|
||||
if (!p) {
|
||||
errs() << "FATAL: failed to allocate " << size << " bytes\n";
|
||||
std::terminate();
|
||||
}
|
||||
return p;
|
||||
}
|
||||
void* CheckedMalloc(size_t size);
|
||||
|
||||
/**
|
||||
* Wrapper around std::realloc that calls std::terminate on out of memory.
|
||||
@@ -50,14 +33,7 @@ inline void* CheckedMalloc(size_t size) {
|
||||
* @param size number of bytes to allocate
|
||||
* @return Pointer to beginning of newly allocated memory.
|
||||
*/
|
||||
inline void* CheckedRealloc(void* ptr, size_t size) {
|
||||
void* p = std::realloc(ptr, size == 0 ? 1 : size);
|
||||
if (!p) {
|
||||
errs() << "FATAL: failed to allocate " << size << " bytes\n";
|
||||
std::terminate();
|
||||
}
|
||||
return p;
|
||||
}
|
||||
void* CheckedRealloc(void* ptr, size_t size);
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_RAW_OS_OSTREAM_H
|
||||
#define LLVM_SUPPORT_RAW_OS_OSTREAM_H
|
||||
#ifndef WPIUTIL_WPI_RAW_OS_OSTREAM_H
|
||||
#define WPIUTIL_WPI_RAW_OS_OSTREAM_H
|
||||
|
||||
#include "wpi/raw_ostream.h"
|
||||
#include <iosfwd>
|
||||
|
||||
@@ -11,22 +11,32 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_RAW_OSTREAM_H
|
||||
#define LLVM_SUPPORT_RAW_OSTREAM_H
|
||||
#ifndef WPIUTIL_WPI_RAW_OSTREAM_H
|
||||
#define WPIUTIL_WPI_RAW_OSTREAM_H
|
||||
|
||||
#include "wpi/ArrayRef.h"
|
||||
#include "wpi/FileSystem.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/StringRef.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <system_error>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
class format_object_base;
|
||||
class FormattedString;
|
||||
class FormattedNumber;
|
||||
template <typename T> class SmallVectorImpl;
|
||||
class FormattedBytes;
|
||||
|
||||
namespace sys {
|
||||
namespace fs {
|
||||
enum OpenFlags : unsigned;
|
||||
} // end namespace fs
|
||||
} // end 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
|
||||
@@ -34,9 +44,6 @@ template <typename T> class SmallVectorImpl;
|
||||
/// 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
|
||||
@@ -66,7 +73,7 @@ private:
|
||||
public:
|
||||
// color order matches ANSI escape sequence, don't change
|
||||
enum Colors {
|
||||
BLACK=0,
|
||||
BLACK = 0,
|
||||
RED,
|
||||
GREEN,
|
||||
YELLOW,
|
||||
@@ -83,6 +90,9 @@ public:
|
||||
OutBufStart = OutBufEnd = OutBufCur = nullptr;
|
||||
}
|
||||
|
||||
raw_ostream(const raw_ostream &) = delete;
|
||||
void operator=(const raw_ostream &) = delete;
|
||||
|
||||
virtual ~raw_ostream();
|
||||
|
||||
/// tell - Return the current offset with the file.
|
||||
@@ -196,7 +206,7 @@ public:
|
||||
return write(Str.data(), Str.length());
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(const wpi::SmallVectorImpl<char> &Str) {
|
||||
raw_ostream &operator<<(const SmallVectorImpl<char> &Str) {
|
||||
return write(Str.data(), Str.size());
|
||||
}
|
||||
|
||||
@@ -205,7 +215,7 @@ public:
|
||||
return write(Arr.data(), Arr.size());
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(const wpi::SmallVectorImpl<uint8_t> &Arr) {
|
||||
raw_ostream &operator<<(const SmallVectorImpl<uint8_t> &Arr) {
|
||||
return write(Arr.data(), Arr.size());
|
||||
}
|
||||
|
||||
@@ -214,6 +224,7 @@ public:
|
||||
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));
|
||||
}
|
||||
@@ -246,9 +257,15 @@ public:
|
||||
// Formatted output, see the formatHex() function in Support/Format.h.
|
||||
raw_ostream &operator<<(const FormattedNumber &);
|
||||
|
||||
// Formatted output, see the format_bytes() function in Support/Format.h.
|
||||
raw_ostream &operator<<(const FormattedBytes &);
|
||||
|
||||
/// indent - Insert 'NumSpaces' spaces.
|
||||
raw_ostream &indent(unsigned NumSpaces);
|
||||
|
||||
/// write_zeros - Insert 'NumZeros' nulls.
|
||||
raw_ostream &write_zeros(unsigned NumZeros);
|
||||
|
||||
/// 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
|
||||
@@ -336,6 +353,8 @@ private:
|
||||
/// 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);
|
||||
|
||||
virtual void anchor();
|
||||
};
|
||||
|
||||
/// An abstract base class for streams implementations that also support a
|
||||
@@ -343,6 +362,7 @@ private:
|
||||
/// 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;
|
||||
void anchor() override;
|
||||
|
||||
public:
|
||||
explicit raw_pwrite_stream(bool Unbuffered = false)
|
||||
@@ -369,9 +389,7 @@ 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;
|
||||
std::error_code EC;
|
||||
|
||||
uint64_t pos;
|
||||
|
||||
@@ -390,7 +408,9 @@ class raw_fd_ostream : public raw_pwrite_stream {
|
||||
size_t preferred_buffer_size() const override;
|
||||
|
||||
/// Set the flag indicating that an output error has been encountered.
|
||||
void error_detected() { Error = true; }
|
||||
void error_detected(std::error_code EC) { this->EC = EC; }
|
||||
|
||||
void anchor() override;
|
||||
|
||||
public:
|
||||
/// Open the specified file for writing. If an error occurs, information
|
||||
@@ -422,13 +442,13 @@ public:
|
||||
/// to the offset specified from the beginning of the file.
|
||||
uint64_t seek(uint64_t off);
|
||||
|
||||
std::error_code error() const { return EC; }
|
||||
|
||||
/// 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;
|
||||
}
|
||||
bool has_error() const { return bool(EC); }
|
||||
|
||||
/// 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
|
||||
@@ -439,9 +459,7 @@ public:
|
||||
/// Unless explicitly silenced."
|
||||
/// - from The Zen of Python, by Tim Peters
|
||||
///
|
||||
void clear_error() {
|
||||
Error = false;
|
||||
}
|
||||
void clear_error() { EC = std::error_code(); }
|
||||
};
|
||||
|
||||
/// This returns a reference to a raw_ostream for standard output. Use it like:
|
||||
@@ -507,7 +525,8 @@ public:
|
||||
explicit raw_svector_ostream(SmallVectorImpl<char> &O) : OS(O) {
|
||||
SetUnbuffered();
|
||||
}
|
||||
~raw_svector_ostream() override {}
|
||||
|
||||
~raw_svector_ostream() override = default;
|
||||
|
||||
void flush() = delete;
|
||||
|
||||
@@ -539,7 +558,8 @@ public:
|
||||
explicit raw_vector_ostream(std::vector<char> &O) : OS(O) {
|
||||
SetUnbuffered();
|
||||
}
|
||||
~raw_vector_ostream() override {}
|
||||
|
||||
~raw_vector_ostream() override = default;
|
||||
|
||||
void flush() = delete;
|
||||
|
||||
@@ -571,7 +591,8 @@ public:
|
||||
explicit raw_usvector_ostream(SmallVectorImpl<uint8_t> &O) : OS(O) {
|
||||
SetUnbuffered();
|
||||
}
|
||||
~raw_usvector_ostream() override {}
|
||||
|
||||
~raw_usvector_ostream() override = default;
|
||||
|
||||
void flush() = delete;
|
||||
|
||||
@@ -603,7 +624,8 @@ public:
|
||||
explicit raw_uvector_ostream(std::vector<uint8_t> &O) : OS(O) {
|
||||
SetUnbuffered();
|
||||
}
|
||||
~raw_uvector_ostream() override {}
|
||||
|
||||
~raw_uvector_ostream() override = default;
|
||||
|
||||
void flush() = delete;
|
||||
|
||||
@@ -623,7 +645,7 @@ class raw_null_ostream : public raw_pwrite_stream {
|
||||
uint64_t current_pos() const override;
|
||||
|
||||
public:
|
||||
explicit raw_null_ostream() {}
|
||||
explicit raw_null_ostream() = default;
|
||||
~raw_null_ostream() override;
|
||||
};
|
||||
|
||||
@@ -636,6 +658,6 @@ public:
|
||||
~buffer_ostream() override { OS << str(); }
|
||||
};
|
||||
|
||||
} // end wpi namespace
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // LLVM_SUPPORT_RAW_OSTREAM_H
|
||||
|
||||
@@ -11,13 +11,17 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_TYPE_TRAITS_H
|
||||
#define LLVM_SUPPORT_TYPE_TRAITS_H
|
||||
#ifndef WPIUTIL_WPI_TYPE_TRAITS_H
|
||||
#define WPIUTIL_WPI_TYPE_TRAITS_H
|
||||
|
||||
#include "wpi/Compiler.h"
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "wpi/Compiler.h"
|
||||
#ifndef __has_feature
|
||||
#define WPI_DEFINED_HAS_FEATURE
|
||||
#define __has_feature(x) 0
|
||||
#endif
|
||||
|
||||
namespace wpi {
|
||||
|
||||
@@ -46,11 +50,11 @@ struct isPodLike {
|
||||
|
||||
// std::pair's are pod-like if their elements are.
|
||||
template<typename T, typename U>
|
||||
struct isPodLike<std::pair<T, 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
|
||||
/// 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
|
||||
@@ -58,7 +62,7 @@ struct isPodLike<std::pair<T, U> > {
|
||||
/// 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;
|
||||
using UnderlyingT = typename std::remove_reference<T>::type;
|
||||
|
||||
public:
|
||||
static const bool value =
|
||||
@@ -69,27 +73,53 @@ public:
|
||||
std::is_convertible<UnderlyingT, unsigned long long>::value);
|
||||
};
|
||||
|
||||
/// \brief If T is a pointer, just return it. If it is not, return T&.
|
||||
/// 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; };
|
||||
struct add_lvalue_reference_if_not_pointer { using type = T &; };
|
||||
|
||||
template <typename T>
|
||||
struct add_lvalue_reference_if_not_pointer<
|
||||
T, typename std::enable_if<std::is_pointer<T>::value>::type> {
|
||||
typedef T type;
|
||||
using type = T;
|
||||
};
|
||||
|
||||
/// \brief If T is a pointer to X, return a pointer to const X. If it is not,
|
||||
/// 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; };
|
||||
struct add_const_past_pointer { using type = const T; };
|
||||
|
||||
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;
|
||||
using type = const typename std::remove_pointer<T>::type *;
|
||||
};
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct const_pointer_or_const_ref {
|
||||
using type = const T &;
|
||||
};
|
||||
template <typename T>
|
||||
struct const_pointer_or_const_ref<
|
||||
T, typename std::enable_if<std::is_pointer<T>::value>::type> {
|
||||
using type = typename add_const_past_pointer<T>::type;
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
// If the compiler supports detecting whether a class is final, define
|
||||
// an LLVM_IS_FINAL macro. If it cannot be defined properly, this
|
||||
// macro will be left undefined.
|
||||
#ifndef LLVM_IS_FINAL
|
||||
#if __cplusplus >= 201402L || defined(_MSC_VER)
|
||||
#define LLVM_IS_FINAL(Ty) std::is_final<Ty>()
|
||||
#elif __has_feature(is_final) || LLVM_GNUC_PREREQ(4, 7, 0)
|
||||
#define LLVM_IS_FINAL(Ty) __is_final(Ty)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef WPI_DEFINED_HAS_FEATURE
|
||||
#undef __has_feature
|
||||
#undef WPI_DEFINED_HAS_FEATURE
|
||||
#endif
|
||||
|
||||
#endif // LLVM_SUPPORT_TYPE_TRAITS_H
|
||||
|
||||
Reference in New Issue
Block a user