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:
Peter Johnson
2018-05-22 23:31:08 -07:00
committed by GitHub
parent 680aabbe7c
commit a2ecb1027a
62 changed files with 5956 additions and 2522 deletions

View File

@@ -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>)> {
};

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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; }

View 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

View File

@@ -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 &current_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 &current_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) {

View File

@@ -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

View File

@@ -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,

View File

@@ -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

View File

@@ -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) {

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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>

View 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

View File

@@ -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().

View File

@@ -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;

View File

@@ -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

View File

@@ -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>

View File

@@ -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

View File

@@ -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