[wpiutil] Vendor llvm and update to 13.0.0 (#4224)

This commit is contained in:
PJ Reiniger
2022-05-20 18:59:53 -04:00
committed by GitHub
parent 5aa67f56e6
commit c3b223ce60
106 changed files with 16897 additions and 1895 deletions

View File

@@ -1,146 +1,34 @@
//===--- AlignOf.h - Portable calculation of type alignment -----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines the AlignedCharArray and AlignedCharArrayUnion classes.
// This file defines the AlignedCharArrayUnion class.
//
//===----------------------------------------------------------------------===//
#ifndef WPIUTIL_WPI_ALIGNOF_H
#define WPIUTIL_WPI_ALIGNOF_H
#include "wpi/Compiler.h"
#include <cstddef>
#include <type_traits>
namespace wpi {
/// \struct AlignedCharArray
/// Helper for building an aligned character array type.
/// A suitably aligned and sized character array member which can hold elements
/// of any 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 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.
// MSVC requires special handling here.
#ifndef _MSC_VER
template<std::size_t Alignment, std::size_t Size>
struct AlignedCharArray {
alignas(Alignment) char buffer[Size];
/// This template is equivalent to std::aligned_union_t<1, ...>, but we cannot
/// use it due to a bug in the MSVC x86 compiler:
/// https://github.com/microsoft/STL/issues/1533
/// Using `alignas` here works around the bug.
template <typename T, typename... Ts> struct AlignedCharArrayUnion {
using AlignedUnion = std::aligned_union_t<1, T, Ts...>;
alignas(alignof(AlignedUnion)) char buffer[sizeof(AlignedUnion)];
};
#else // _MSC_VER
/// Create a type with an aligned char buffer.
template<std::size_t Alignment, std::size_t Size>
struct AlignedCharArray;
// We provide special variations of this template for the most common
// alignments because __declspec(align(...)) doesn't actually work when it is
// a member of a by-value function argument in MSVC, even if the alignment
// request is something reasonably like 8-byte or 16-byte. Note that we can't
// even include the declspec with the union that forces the alignment because
// MSVC warns on the existence of the declspec despite the union member forcing
// proper alignment.
template<std::size_t Size>
struct AlignedCharArray<1, Size> {
union {
char aligned;
char buffer[Size];
};
};
template<std::size_t Size>
struct AlignedCharArray<2, Size> {
union {
short aligned;
char buffer[Size];
};
};
template<std::size_t Size>
struct AlignedCharArray<4, Size> {
union {
int aligned;
char buffer[Size];
};
};
template<std::size_t Size>
struct AlignedCharArray<8, Size> {
union {
double aligned;
char buffer[Size];
};
};
// The rest of these are provided with a __declspec(align(...)) and we simply
// can't pass them by-value as function arguments on MSVC.
#define LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(x) \
template<std::size_t Size> \
struct AlignedCharArray<x, Size> { \
__declspec(align(x)) char buffer[Size]; \
};
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(16)
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(32)
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(64)
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(128)
#undef LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT
#endif // _MSC_VER
namespace detail {
template <typename T1,
typename T2 = char, typename T3 = char, typename T4 = char,
typename T5 = char, typename T6 = char, typename T7 = char,
typename T8 = char, typename T9 = char, typename T10 = char>
class AlignerImpl {
T1 t1; T2 t2; T3 t3; T4 t4; T5 t5; T6 t6; T7 t7; T8 t8; T9 t9; T10 t10;
AlignerImpl() = delete;
};
template <typename T1,
typename T2 = char, typename T3 = char, typename T4 = char,
typename T5 = char, typename T6 = char, typename T7 = char,
typename T8 = char, typename T9 = char, typename T10 = char>
union SizerImpl {
char arr1[sizeof(T1)], arr2[sizeof(T2)], arr3[sizeof(T3)], arr4[sizeof(T4)],
arr5[sizeof(T5)], arr6[sizeof(T6)], arr7[sizeof(T7)], arr8[sizeof(T8)],
arr9[sizeof(T9)], arr10[sizeof(T10)];
};
} // end namespace detail
/// This union template exposes a suitably aligned and sized character
/// array member which can hold elements of any of up to ten types.
///
/// These types may be arrays, structs, or any other types. The goal is to
/// expose a char array buffer member which can be used as suitable storage for
/// a placement new of any of these types. Support for more than ten types can
/// be added at the cost of more boilerplate.
template <typename T1,
typename T2 = char, typename T3 = char, typename T4 = char,
typename T5 = char, typename T6 = char, typename T7 = char,
typename T8 = char, typename T9 = char, typename T10 = char>
struct AlignedCharArrayUnion : wpi::AlignedCharArray<
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>)> {
};
} // end namespace wpi
#endif // LLVM_SUPPORT_ALIGNOF_H
#endif // WPIUTIL_WPI_ALIGNOF_H

View File

@@ -1,9 +1,8 @@
//===- llvm/Support/Chrono.h - Utilities for Timing Manipulation-*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -33,21 +32,21 @@ template <typename D = std::chrono::nanoseconds>
using TimePoint = std::chrono::time_point<std::chrono::system_clock, D>;
/// Convert a TimePoint to std::time_t
LLVM_ATTRIBUTE_ALWAYS_INLINE std::time_t toTimeT(TimePoint<> TP) {
inline std::time_t toTimeT(TimePoint<> TP) {
using namespace std::chrono;
return system_clock::to_time_t(
time_point_cast<system_clock::time_point::duration>(TP));
}
/// Convert a std::time_t to a TimePoint
LLVM_ATTRIBUTE_ALWAYS_INLINE TimePoint<std::chrono::seconds>
inline TimePoint<std::chrono::seconds>
toTimePoint(std::time_t T) {
using namespace std::chrono;
return time_point_cast<seconds>(system_clock::from_time_t(T));
}
/// Convert a std::time_t + nanoseconds to a TimePoint
LLVM_ATTRIBUTE_ALWAYS_INLINE TimePoint<>
inline TimePoint<>
toTimePoint(std::time_t T, uint32_t nsec) {
using namespace std::chrono;
return time_point_cast<nanoseconds>(system_clock::from_time_t(T))

View File

@@ -1,21 +1,24 @@
//===-- llvm/Support/Compiler.h - Compiler abstraction support --*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines several macros, based on the current compiler. This allows
// use of compiler-specific features in a way that remains portable.
// use of compiler-specific features in a way that remains portable. This header
// can be included from either C or C++.
//
//===----------------------------------------------------------------------===//
#ifndef WPIUTIL_WPI_COMPILER_H
#define WPIUTIL_WPI_COMPILER_H
#ifdef __cplusplus
#include <new>
#endif
#include <stddef.h>
#if defined(_MSC_VER)
@@ -34,14 +37,20 @@
# 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
// Only use __has_cpp_attribute in C++ mode. GCC defines __has_cpp_attribute in
// C mode, but the :: in __has_cpp_attribute(scoped::attribute) is invalid.
#ifndef LLVM_HAS_CPP_ATTRIBUTE
#if defined(__cplusplus) && defined(__has_cpp_attribute)
# define LLVM_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
#else
# define LLVM_HAS_CPP_ATTRIBUTE(x) 0
#endif
#endif
/// \macro LLVM_GNUC_PREREQ
/// Extend the default __GNUC_PREREQ even if glibc's features.h isn't
/// available.
@@ -61,14 +70,22 @@
/// \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
/// * 1910: VS2017, version 15.1 & 15.2
/// * 1911: VS2017, version 15.3 & 15.4
/// * 1912: VS2017, version 15.5
/// * 1913: VS2017, version 15.6
/// * 1914: VS2017, version 15.7
/// * 1915: VS2017, version 15.8
/// * 1916: VS2017, version 15.9
/// * 1920: VS2019, version 16.0
/// * 1921: VS2019, version 16.1
#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.
// We require at least MSVC 2017.
#if !LLVM_MSC_PREREQ(1910)
#error LLVM requires at least MSVC 2017.
#endif
#else
@@ -79,9 +96,11 @@
/// 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.
/// and MSVC implemented this later than everything else. This appears to be
/// corrected in MSVC 2019 but not MSVC 2017.
#ifndef LLVM_HAS_RVALUE_REFERENCE_THIS
#if __has_feature(cxx_rvalue_references) || LLVM_GNUC_PREREQ(4, 8, 1)
#if __has_feature(cxx_rvalue_references) || LLVM_GNUC_PREREQ(4, 8, 1) || \
LLVM_MSC_PREREQ(1920)
#define LLVM_HAS_RVALUE_REFERENCE_THIS 1
#else
#define LLVM_HAS_RVALUE_REFERENCE_THIS 0
@@ -100,6 +119,24 @@
#endif
#endif
/// LLVM_LIBRARY_VISIBILITY - If a class marked with this attribute is linked
/// into a shared library, then the class should be private to the library and
/// not accessible from outside it. Can also be used to mark variables and
/// functions, making them private to any shared library they are linked into.
/// On PE/COFF targets, library visibility is the default, so this isn't needed.
///
/// LLVM_EXTERNAL_VISIBILITY - classes, functions, and variables marked with
/// this attribute will be made public and visible outside of any shared library
/// they are linked in to.
#if (__has_attribute(visibility) || LLVM_GNUC_PREREQ(4, 0, 0)) && \
!defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(_WIN32)
#define LLVM_LIBRARY_VISIBILITY __attribute__ ((visibility("hidden")))
#define LLVM_EXTERNAL_VISIBILITY __attribute__ ((visibility("default")))
#else
#define LLVM_LIBRARY_VISIBILITY
#define LLVM_EXTERNAL_VISIBILITY
#endif
#ifndef LLVM_PREFETCH
#if defined(__GNUC__)
#define LLVM_PREFETCH(addr, rw, locality) __builtin_prefetch(addr, rw, locality)
@@ -117,25 +154,37 @@
#endif
/// LLVM_NODISCARD - Warn if a type or return value is discarded.
// Use the 'nodiscard' attribute in C++17 or newer mode.
#ifndef LLVM_NODISCARD
#if __cplusplus > 201402L && __has_cpp_attribute(nodiscard)
#if defined(__cplusplus) && __cplusplus > 201402L && LLVM_HAS_CPP_ATTRIBUTE(nodiscard)
#define LLVM_NODISCARD [[nodiscard]]
// Detect MSVC directly, since __cplusplus still defaults to old version
#elif _MSVC_LANG >= 201703L
#define LLVM_NODISCARD [[nodiscard]]
#elif _MSC_VER
#define LLVM_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)
#elif LLVM_HAS_CPP_ATTRIBUTE(clang::warn_unused_result)
#define LLVM_NODISCARD [[clang::warn_unused_result]]
// Clang in C++14 mode claims that it has the 'nodiscard' attribute, but also
// warns in the pedantic mode that 'nodiscard' is a C++17 extension (PR33518).
// Use the 'nodiscard' attribute in C++14 mode only with GCC.
// TODO: remove this workaround when PR33518 is resolved.
#elif defined(__GNUC__) && LLVM_HAS_CPP_ATTRIBUTE(nodiscard)
#define LLVM_NODISCARD [[nodiscard]]
#else
#define LLVM_NODISCARD
#endif
#endif
// Indicate that a non-static, non-const C++ member function reinitializes
// the entire object to a known state, independent of the previous state of
// the object.
//
// The clang-tidy check bugprone-use-after-move recognizes this attribute as a
// marker that a moved-from object has left the indeterminate state and can be
// reused.
#if LLVM_HAS_CPP_ATTRIBUTE(clang::reinitializes)
#define LLVM_ATTRIBUTE_REINITIALIZES [[clang::reinitializes]]
#else
#define LLVM_ATTRIBUTE_REINITIALIZES
#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.
@@ -152,6 +201,14 @@
#endif
#endif
// FIXME: Provide this for PE/COFF targets.
#if (__has_attribute(weak) || LLVM_GNUC_PREREQ(4, 0, 0)) && \
(!defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(_WIN32))
#define LLVM_ATTRIBUTE_WEAK __attribute__((__weak__))
#else
#define LLVM_ATTRIBUTE_WEAK
#endif
#ifndef LLVM_READNONE
// Prior to clang 3.2, clang did not accept any spelling of
// __has_attribute(const), so assume it is supported.
@@ -200,7 +257,7 @@
/// 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
#define LLVM_ATTRIBUTE_ALWAYS_INLINE inline __attribute__((always_inline))
#elif defined(_MSC_VER)
#define LLVM_ATTRIBUTE_ALWAYS_INLINE __forceinline
#else
@@ -242,26 +299,44 @@
/// LLVM_FALLTHROUGH - Mark fallthrough cases in switch statements.
#ifndef LLVM_FALLTHROUGH
#if __cplusplus > 201402L && __has_cpp_attribute(fallthrough)
#if defined(__cplusplus) && __cplusplus > 201402L && LLVM_HAS_CPP_ATTRIBUTE(fallthrough)
#define LLVM_FALLTHROUGH [[fallthrough]]
// Detect MSVC directly, since __cplusplus still defaults to old version
#elif _MSVC_LANG >= 201703L
#define LLVM_FALLTHROUGH [[fallthrough]]
#elif _MSC_VER
#define LLVM_FALLTHROUGH
#elif __has_cpp_attribute(gnu::fallthrough)
#elif LLVM_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)
#elif __has_attribute(fallthrough)
#define LLVM_FALLTHROUGH __attribute__((fallthrough))
#elif LLVM_HAS_CPP_ATTRIBUTE(clang::fallthrough)
#define LLVM_FALLTHROUGH [[clang::fallthrough]]
#else
#define LLVM_FALLTHROUGH
#endif
#endif
/// LLVM_REQUIRE_CONSTANT_INITIALIZATION - Apply this to globals to ensure that
/// they are constant initialized.
#if LLVM_HAS_CPP_ATTRIBUTE(clang::require_constant_initialization)
#define LLVM_REQUIRE_CONSTANT_INITIALIZATION \
[[clang::require_constant_initialization]]
#else
#define LLVM_REQUIRE_CONSTANT_INITIALIZATION
#endif
/// LLVM_GSL_OWNER - Apply this to owning classes like SmallVector to enable
/// lifetime warnings.
#if LLVM_HAS_CPP_ATTRIBUTE(gsl::Owner)
#define LLVM_GSL_OWNER [[gsl::Owner]]
#else
#define LLVM_GSL_OWNER
#endif
/// LLVM_GSL_POINTER - Apply this to non-owning classes like
/// std::string_view to enable lifetime warnings.
#if LLVM_HAS_CPP_ATTRIBUTE(gsl::Pointer)
#define LLVM_GSL_POINTER [[gsl::Pointer]]
#else
#define LLVM_GSL_POINTER
#endif
/// LLVM_EXTENSION - Support compilers where we have a keyword to suppress
/// pedantic diagnostics.
#ifndef LLVM_EXTENSION
@@ -273,20 +348,10 @@
#endif
// LLVM_ATTRIBUTE_DEPRECATED(decl, "message")
// This macro will be removed.
// Use C++14's attribute instead: [[deprecated("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
#define LLVM_ATTRIBUTE_DEPRECATED(decl, message) [[deprecated(message)]] decl
#endif
/// LLVM_BUILTIN_UNREACHABLE - On compilers which support it, expands
@@ -341,7 +406,6 @@
#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
@@ -349,16 +413,6 @@
#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(
@@ -391,8 +445,8 @@
/// \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.
/// Generally used in combination with alignas or when doing computation in the
/// preprocessor.
#ifndef LLVM_PTR_SIZE
#ifdef __SIZEOF_POINTER__
# define LLVM_PTR_SIZE __SIZEOF_POINTER__
@@ -407,6 +461,73 @@
#endif
#endif
/// \macro LLVM_MEMORY_SANITIZER_BUILD
/// Whether LLVM itself is built with MemorySanitizer instrumentation.
#if __has_feature(memory_sanitizer)
# define LLVM_MEMORY_SANITIZER_BUILD 1
# include <sanitizer/msan_interface.h>
# define LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE __attribute__((no_sanitize_memory))
#else
# define LLVM_MEMORY_SANITIZER_BUILD 0
# define __msan_allocated_memory(p, size)
# define __msan_unpoison(p, size)
# define LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE
#endif
/// \macro LLVM_ADDRESS_SANITIZER_BUILD
/// Whether LLVM itself is built with AddressSanitizer instrumentation.
#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
# define LLVM_ADDRESS_SANITIZER_BUILD 1
# include <sanitizer/asan_interface.h>
#else
# define LLVM_ADDRESS_SANITIZER_BUILD 0
# define __asan_poison_memory_region(p, size)
# define __asan_unpoison_memory_region(p, size)
#endif
/// \macro LLVM_THREAD_SANITIZER_BUILD
/// Whether LLVM itself is built with ThreadSanitizer instrumentation.
#if __has_feature(thread_sanitizer) || defined(__SANITIZE_THREAD__)
# define LLVM_THREAD_SANITIZER_BUILD 1
#else
# define LLVM_THREAD_SANITIZER_BUILD 0
#endif
#if LLVM_THREAD_SANITIZER_BUILD
// Thread Sanitizer is a tool that finds races in code.
// See http://code.google.com/p/data-race-test/wiki/DynamicAnnotations .
// tsan detects these exact functions by name.
#ifdef __cplusplus
extern "C" {
#endif
void AnnotateHappensAfter(const char *file, int line, const volatile void *cv);
void AnnotateHappensBefore(const char *file, int line, const volatile void *cv);
void AnnotateIgnoreWritesBegin(const char *file, int line);
void AnnotateIgnoreWritesEnd(const char *file, int line);
#ifdef __cplusplus
}
#endif
// This marker is used to define a happens-before arc. The race detector will
// infer an arc from the begin to the end when they share the same pointer
// argument.
# define TsanHappensBefore(cv) AnnotateHappensBefore(__FILE__, __LINE__, cv)
// This marker defines the destination of a happens-before arc.
# define TsanHappensAfter(cv) AnnotateHappensAfter(__FILE__, __LINE__, cv)
// Ignore any races on writes between here and the next TsanIgnoreWritesEnd.
# define TsanIgnoreWritesBegin() AnnotateIgnoreWritesBegin(__FILE__, __LINE__)
// Resume checking for racy writes.
# define TsanIgnoreWritesEnd() AnnotateIgnoreWritesEnd(__FILE__, __LINE__)
#else
# define TsanHappensBefore(cv)
# define TsanHappensAfter(cv)
# define TsanIgnoreWritesBegin()
# define TsanIgnoreWritesEnd()
#endif
/// \macro LLVM_NO_SANITIZE
/// Disable a particular sanitizer for a function.
#ifndef LLVM_NO_SANITIZE
@@ -451,66 +572,28 @@
/// 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)
/// support. It uses thread_local if available, falling back on gcc __thread
/// if not. __thread doesn'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.
#if __has_feature(cxx_thread_local) || defined(_MSC_VER)
#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
/// \macro LLVM_ENABLE_EXCEPTIONS
/// Whether LLVM is built with exception support.
#if __has_feature(cxx_exceptions)
#define LLVM_ENABLE_EXCEPTIONS 1
#elif defined(__GNUC__) && defined(__EXCEPTIONS)
#define LLVM_ENABLE_EXCEPTIONS 1
#elif defined(_MSC_VER) && defined(_CPPUNWIND)
#define LLVM_ENABLE_EXCEPTIONS 1
#endif
namespace wpi {
/// Allocate a buffer of memory with the given size and alignment.
///
/// When the compiler supports aligned operator new, this will use it to to
/// handle even over-aligned allocations.
///
/// However, this doesn't make any attempt to leverage the fancier techniques
/// like posix_memalign due to portability. It is mostly intended to allow
/// compatibility with platforms that, after aligned allocation was added, use
/// reduced default alignment.
inline void *allocate_buffer(size_t Size, size_t Alignment) {
return ::operator new(Size
#ifdef __cpp_aligned_new
,
std::align_val_t(Alignment)
#endif
);
}
/// Deallocate a buffer of memory with the given size and alignment.
///
/// If supported, this will used the sized delete operator. Also if supported,
/// this will pass the alignment to the delete operator.
///
/// The pointer must have been allocated with the corresponding new operator,
/// most likely using the above helper.
inline void deallocate_buffer(void *Ptr, size_t Size, size_t Alignment) {
::operator delete(Ptr
#ifdef __cpp_sized_deallocation
,
Size
#endif
#ifdef __cpp_aligned_new
,
std::align_val_t(Alignment)
#endif
);
}
} // End namespace wpi
#endif

View File

@@ -1,9 +1,8 @@
/*===--- ConvertUTF.h - Universal Character Names conversions ---------------===
*
* The LLVM Compiler Infrastructure
*
* This file is distributed under the University of Illinois Open Source
* License. See LICENSE.TXT for details.
* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
* See https://llvm.org/LICENSE.txt for license information.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*
*==------------------------------------------------------------------------==*/
/*
@@ -87,8 +86,8 @@
------------------------------------------------------------------------ */
#ifndef LLVM_SUPPORT_CONVERTUTF_H
#define LLVM_SUPPORT_CONVERTUTF_H
#ifndef WPIUTIL_WPI_CONVERTUTF_H
#define WPIUTIL_WPI_CONVERTUTF_H
#include "wpi/span.h"
@@ -97,14 +96,11 @@
#include <string_view>
#include <system_error>
// Wrap everything in namespace wpi so that programs can link with wpiutil and
// Wrap everything in namespace wpi so that programs can link with llvm and
// their own version of the unicode libraries.
namespace wpi {
template <typename T>
class SmallVectorImpl;
/* ---------------------------------------------------------------------
The following 4 definitions are compiler-specific.
The C standard does not guarantee that wchar_t has at least
@@ -187,6 +183,38 @@ unsigned getNumBytesForUTF8(UTF8 firstByte);
/*************************************************************************/
/* Below are LLVM-specific wrappers of the functions above. */
template <typename T> class SmallVectorImpl;
/**
* Convert an UTF8 string_view to UTF8, UTF16, or UTF32 depending on
* WideCharWidth. The converted data is written to ResultPtr, which needs to
* point to at least WideCharWidth * (Source.Size() + 1) bytes. On success,
* ResultPtr will point one after the end of the copied string. On failure,
* ResultPtr will not be changed, and ErrorPtr will be set to the location of
* the first character which could not be converted.
* \return true on success.
*/
bool ConvertUTF8toWide(unsigned WideCharWidth, std::string_view Source,
char *&ResultPtr, const UTF8 *&ErrorPtr);
/**
* Converts a UTF-8 string_view to a std::wstring.
* \return true on success.
*/
bool ConvertUTF8toWide(std::string_view Source, std::wstring &Result);
/**
* Converts a UTF-8 C-string to a std::wstring.
* \return true on success.
*/
bool ConvertUTF8toWide(const char *Source, std::wstring &Result);
/**
* Converts a std::wstring to a UTF-8 encoded std::string.
* \return true on success.
*/
bool convertWideToUTF8(const std::wstring &Source, SmallVectorImpl<char> &Result);
/**
* Convert an Unicode code point to UTF8 sequence.
@@ -215,10 +243,10 @@ bool ConvertCodePointToUTF8(unsigned Source, char *&ResultPtr);
*
* \sa ConvertUTF8toUTF32
*/
static inline ConversionResult convertUTF8Sequence(const UTF8 **source,
const UTF8 *sourceEnd,
UTF32 *target,
ConversionFlags flags) {
inline ConversionResult convertUTF8Sequence(const UTF8 **source,
const UTF8 *sourceEnd,
UTF32 *target,
ConversionFlags flags) {
if (*source == sourceEnd)
return sourceExhausted;
unsigned size = getNumBytesForUTF8(**source);
@@ -234,12 +262,22 @@ static inline ConversionResult convertUTF8Sequence(const UTF8 **source,
bool hasUTF16ByteOrderMark(span<const char> SrcBytes);
/**
* Converts a UTF-16 string into a UTF-8 string.
* Converts a stream of raw bytes assumed to be UTF16 into a UTF8 std::string.
*
* \param [in] SrcBytes A buffer of what is assumed to be UTF-16 encoded text.
* \param [out] Out Converted UTF-8 is stored here on success.
* \returns true on success
*/
bool convertUTF16ToUTF8String(span<const UTF16> SrcUTF16,
SmallVectorImpl<char> &DstUTF8);
bool convertUTF16ToUTF8String(span<const char> SrcBytes, SmallVectorImpl<char> &Out);
/**
* Converts a UTF16 string into a UTF8 std::string.
*
* \param [in] Src A buffer of UTF-16 encoded text.
* \param [out] Out Converted UTF-8 is stored here on success.
* \returns true on success
*/
bool convertUTF16ToUTF8String(span<const UTF16> Src, SmallVectorImpl<char> &Out);
/**
* Converts a UTF-8 string into a UTF-16 string with native endianness.

View File

@@ -1,9 +1,8 @@
//===- llvm/ADT/DenseMap.h - Dense probed hash table ------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -19,12 +18,14 @@
#include "wpi/AlignOf.h"
#include "wpi/Compiler.h"
#include "wpi/MathExtras.h"
#include "wpi/MemAlloc.h"
#include "wpi/PointerLikeTypeTraits.h"
#include "wpi/type_traits.h"
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstring>
#include <initializer_list>
#include <iterator>
#include <new>
#include <type_traits>
@@ -38,6 +39,8 @@ namespace detail {
// implementation without requiring two members.
template <typename KeyT, typename ValueT>
struct DenseMapPair : public std::pair<KeyT, ValueT> {
using std::pair<KeyT, ValueT>::pair;
KeyT &getFirst() { return std::pair<KeyT, ValueT>::first; }
const KeyT &getFirst() const { return std::pair<KeyT, ValueT>::first; }
ValueT &getSecond() { return std::pair<KeyT, ValueT>::second; }
@@ -113,8 +116,8 @@ public:
}
const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey();
if (isPodLike<KeyT>::value && isPodLike<ValueT>::value) {
// Use a simpler loop when these are trivial types.
if (std::is_trivially_destructible<ValueT>::value) {
// Use a simpler loop when values don't need destruction.
for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P)
P->getFirst() = EmptyKey;
} else {
@@ -143,13 +146,15 @@ public:
iterator find(const_arg_type_t<KeyT> Val) {
BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
return makeIterator(TheBucket, getBucketsEnd(), *this, true);
return makeIterator(TheBucket, getBucketsEnd(),
*this, true);
return end();
}
const_iterator find(const_arg_type_t<KeyT> Val) const {
const BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
return makeConstIterator(TheBucket, getBucketsEnd(), *this, true);
return makeConstIterator(TheBucket, getBucketsEnd(),
*this, true);
return end();
}
@@ -162,14 +167,16 @@ public:
iterator find_as(const LookupKeyT &Val) {
BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
return makeIterator(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 makeConstIterator(TheBucket, getBucketsEnd(), *this, true);
return makeConstIterator(TheBucket, getBucketsEnd(),
*this, true);
return end();
}
@@ -203,16 +210,16 @@ public:
std::pair<iterator, bool> try_emplace(KeyT &&Key, Ts &&... Args) {
BucketT *TheBucket;
if (LookupBucketFor(Key, TheBucket))
return std::make_pair(
makeIterator(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(TheBucket, std::move(Key), std::forward<Ts>(Args)...);
return std::make_pair(
makeIterator(TheBucket, getBucketsEnd(), *this, true),
true);
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.
@@ -222,15 +229,15 @@ public:
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.
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);
return std::make_pair(makeIterator(TheBucket, getBucketsEnd(),
*this, true),
true);
}
/// Alternate version of insert() which allows a different, and possibly
@@ -243,16 +250,16 @@ public:
const LookupKeyT &Val) {
BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
return std::make_pair(
makeIterator(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 = InsertIntoBucketWithLookup(TheBucket, std::move(KV.first),
std::move(KV.second), Val);
return std::make_pair(
makeIterator(TheBucket, getBucketsEnd(), *this, true),
true);
return std::make_pair(makeIterator(TheBucket, getBucketsEnd(),
*this, true),
true);
}
/// insert - Range insertion of pairs.
@@ -389,7 +396,8 @@ protected:
setNumEntries(other.getNumEntries());
setNumTombstones(other.getNumTombstones());
if (isPodLike<KeyT>::value && isPodLike<ValueT>::value)
if (std::is_trivially_copyable<KeyT>::value &&
std::is_trivially_copyable<ValueT>::value)
memcpy(reinterpret_cast<void *>(getBuckets()), other.getBuckets(),
getNumBuckets() * sizeof(BucketT));
else
@@ -679,7 +687,7 @@ class DenseMap : public DenseMapBase<DenseMap<KeyT, ValueT, KeyInfoT, BucketT>,
unsigned NumBuckets;
public:
/// Create a DenseMap wth an optional \p InitialReserve that guarantee that
/// Create a DenseMap with an optional \p InitialReserve that guarantee that
/// this number of elements can be inserted in the map without grow()
explicit DenseMap(unsigned InitialReserve = 0) { init(InitialReserve); }
@@ -706,7 +714,7 @@ public:
~DenseMap() {
this->destroyAll();
operator delete(Buckets);
deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets, alignof(BucketT));
}
void swap(DenseMap& RHS) {
@@ -726,7 +734,7 @@ public:
DenseMap& operator=(DenseMap &&other) {
this->destroyAll();
operator delete(Buckets);
deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets, alignof(BucketT));
init(0);
swap(other);
return *this;
@@ -734,7 +742,7 @@ public:
void copyFrom(const DenseMap& other) {
this->destroyAll();
operator delete(Buckets);
deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets, alignof(BucketT));
if (allocateBuckets(other.NumBuckets)) {
this->BaseT::copyFrom(other);
} else {
@@ -767,10 +775,12 @@ public:
this->moveFromOldBuckets(OldBuckets, OldBuckets+OldNumBuckets);
// Free the old table.
operator delete(OldBuckets);
deallocate_buffer(OldBuckets, sizeof(BucketT) * OldNumBuckets,
alignof(BucketT));
}
void shrink_and_clear() {
unsigned OldNumBuckets = NumBuckets;
unsigned OldNumEntries = NumEntries;
this->destroyAll();
@@ -783,7 +793,8 @@ public:
return;
}
operator delete(Buckets);
deallocate_buffer(Buckets, sizeof(BucketT) * OldNumBuckets,
alignof(BucketT));
init(NewNumBuckets);
}
@@ -819,7 +830,8 @@ private:
return false;
}
Buckets = static_cast<BucketT*>(operator new(sizeof(BucketT) * NumBuckets));
Buckets = static_cast<BucketT *>(
allocate_buffer(sizeof(BucketT) * NumBuckets, alignof(BucketT)));
return true;
}
};
@@ -874,6 +886,9 @@ public:
this->insert(I, E);
}
SmallDenseMap(std::initializer_list<typename BaseT::value_type> Vals)
: SmallDenseMap(Vals.begin(), Vals.end()) {}
~SmallDenseMap() {
this->destroyAll();
deallocateBuckets();
@@ -904,7 +919,7 @@ public:
std::swap(*LHSB, *RHSB);
continue;
}
// Swap separately and handle any assymetry.
// Swap separately and handle any asymmetry.
std::swap(LHSB->getFirst(), RHSB->getFirst());
if (hasLHSValue) {
::new (&RHSB->getSecond()) ValueT(std::move(LHSB->getSecond()));
@@ -986,16 +1001,13 @@ public:
}
void grow(unsigned AtLeast) {
if (AtLeast >= InlineBuckets)
if (AtLeast > InlineBuckets)
AtLeast = std::max<unsigned>(64, NextPowerOf2(AtLeast-1));
if (Small) {
if (AtLeast < InlineBuckets)
return; // Nothing to do.
// First move the inline buckets into a temporary storage.
AlignedCharArrayUnion<BucketT[InlineBuckets]> TmpStorage;
BucketT *TmpBegin = reinterpret_cast<BucketT *>(TmpStorage.buffer);
BucketT *TmpBegin = reinterpret_cast<BucketT *>(&TmpStorage);
BucketT *TmpEnd = TmpBegin;
// Loop over the buckets, moving non-empty, non-tombstones into the
@@ -1015,10 +1027,13 @@ public:
P->getFirst().~KeyT();
}
// Now make this map use the large rep, and move all the entries back
// into it.
Small = false;
new (getLargeRep()) LargeRep(allocateBuckets(AtLeast));
// AtLeast == InlineBuckets can happen if there are many tombstones,
// and grow() is used to remove them. Usually we always switch to the
// large rep here.
if (AtLeast > InlineBuckets) {
Small = false;
new (getLargeRep()) LargeRep(allocateBuckets(AtLeast));
}
this->moveFromOldBuckets(TmpBegin, TmpEnd);
return;
}
@@ -1034,7 +1049,8 @@ public:
this->moveFromOldBuckets(OldRep.Buckets, OldRep.Buckets+OldRep.NumBuckets);
// Free the old table.
operator delete(OldRep.Buckets);
deallocate_buffer(OldRep.Buckets, sizeof(BucketT) * OldRep.NumBuckets,
alignof(BucketT));
}
void shrink_and_clear() {
@@ -1081,8 +1097,8 @@ private:
assert(Small);
// Note that this cast does not violate aliasing rules as we assert that
// the memory's dynamic type is the small, inline bucket buffer, and the
// 'storage.buffer' static type is 'char *'.
return reinterpret_cast<const BucketT *>(storage.buffer);
// 'storage' is a POD containing a char buffer.
return reinterpret_cast<const BucketT *>(&storage);
}
BucketT *getInlineBuckets() {
@@ -1093,7 +1109,7 @@ private:
const LargeRep *getLargeRep() const {
assert(!Small);
// Note, same rule about aliasing as with getInlineBuckets.
return reinterpret_cast<const LargeRep *>(storage.buffer);
return reinterpret_cast<const LargeRep *>(&storage);
}
LargeRep *getLargeRep() {
@@ -1118,15 +1134,17 @@ private:
if (Small)
return;
operator delete(getLargeRep()->Buckets);
deallocate_buffer(getLargeRep()->Buckets,
sizeof(BucketT) * getLargeRep()->NumBuckets,
alignof(BucketT));
getLargeRep()->~LargeRep();
}
LargeRep allocateBuckets(unsigned Num) {
assert(Num > InlineBuckets && "Must allocate more buckets than are inline");
LargeRep Rep = {
static_cast<BucketT*>(operator new(sizeof(BucketT) * Num)), Num
};
LargeRep Rep = {static_cast<BucketT *>(allocate_buffer(
sizeof(BucketT) * Num, alignof(BucketT))),
Num};
return Rep;
}
};
@@ -1137,8 +1155,6 @@ class DenseMapIterator : DebugEpochBase::HandleBase {
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:
using difference_type = ptrdiff_t;
using value_type =
@@ -1167,7 +1183,7 @@ public:
// for const iterator destinations so it doesn't end up as a user defined copy
// constructor.
template <bool IsConstSrc,
typename = typename std::enable_if<!IsConstSrc && IsConst>::type>
typename = std::enable_if_t<!IsConstSrc && IsConst>>
DenseMapIterator(
const DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, IsConstSrc> &I)
: DebugEpochBase::HandleBase(I), Ptr(I.Ptr), End(I.End) {}
@@ -1181,19 +1197,18 @@ public:
return Ptr;
}
bool operator==(const ConstIterator &RHS) const {
assert((!Ptr || isHandleInSync()) && "handle not in sync!");
friend bool operator==(const DenseMapIterator &LHS,
const DenseMapIterator &RHS) {
assert((!LHS.Ptr || LHS.isHandleInSync()) && "handle not in sync!");
assert((!RHS.Ptr || RHS.isHandleInSync()) && "handle not in sync!");
assert(getEpochAddress() == RHS.getEpochAddress() &&
assert(LHS.getEpochAddress() == RHS.getEpochAddress() &&
"comparing incomparable iterators!");
return Ptr == RHS.Ptr;
return LHS.Ptr == RHS.Ptr;
}
bool operator!=(const ConstIterator &RHS) const {
assert((!Ptr || isHandleInSync()) && "handle not in sync!");
assert((!RHS.Ptr || RHS.isHandleInSync()) && "handle not in sync!");
assert(getEpochAddress() == RHS.getEpochAddress() &&
"comparing incomparable iterators!");
return Ptr != RHS.Ptr;
friend bool operator!=(const DenseMapIterator &LHS,
const DenseMapIterator &RHS) {
return !(LHS == RHS);
}
inline DenseMapIterator& operator++() { // Preincrement
@@ -1236,4 +1251,4 @@ inline size_t capacity_in_bytes(const DenseMap<KeyT, ValueT, KeyInfoT> &X) {
} // end namespace wpi
#endif // LLVM_ADT_DENSEMAP_H
#endif // WPIUTIL_WPI_DENSEMAP_H

View File

@@ -1,9 +1,8 @@
//===- llvm/ADT/DenseMapInfo.h - Type traits for DenseMap -------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -15,16 +14,31 @@
#define WPIUTIL_WPI_DENSEMAPINFO_H
#include "wpi/Hashing.h"
#include "wpi/PointerLikeTypeTraits.h"
#include "wpi/span.h"
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <string_view>
#include <utility>
namespace wpi {
namespace detail {
/// Simplistic combination of 32-bit hash values into 32-bit hash values.
static inline unsigned combineHashValue(unsigned a, unsigned b) {
uint64_t key = (uint64_t)a << 32 | (uint64_t)b;
key += ~(key << 32);
key ^= (key >> 22);
key += ~(key << 13);
key ^= (key >> 8);
key += (key << 3);
key ^= (key >> 15);
key += ~(key << 27);
key ^= (key >> 31);
return (unsigned)key;
}
} // end namespace detail
template<typename T>
struct DenseMapInfo {
//static inline T getEmptyKey();
@@ -33,18 +47,28 @@ struct DenseMapInfo {
//static bool isEqual(const T &LHS, const T &RHS);
};
// Provide DenseMapInfo for all pointers.
// Provide DenseMapInfo for all pointers. Come up with sentinel pointer values
// that are aligned to alignof(T) bytes, but try to avoid requiring T to be
// complete. This allows clients to instantiate DenseMap<T*, ...> with forward
// declared key types. Assume that no pointer key type requires more than 4096
// bytes of alignment.
template<typename T>
struct DenseMapInfo<T*> {
// The following should hold, but it would require T to be complete:
// static_assert(alignof(T) <= (1 << Log2MaxAlign),
// "DenseMap does not support pointer keys requiring more than "
// "Log2MaxAlign bits of alignment");
static constexpr uintptr_t Log2MaxAlign = 12;
static inline T* getEmptyKey() {
uintptr_t Val = static_cast<uintptr_t>(-1);
Val <<= PointerLikeTypeTraits<T*>::NumLowBitsAvailable;
Val <<= Log2MaxAlign;
return reinterpret_cast<T*>(Val);
}
static inline T* getTombstoneKey() {
uintptr_t Val = static_cast<uintptr_t>(-2);
Val <<= PointerLikeTypeTraits<T*>::NumLowBitsAvailable;
Val <<= Log2MaxAlign;
return reinterpret_cast<T*>(Val);
}
@@ -67,6 +91,17 @@ template<> struct DenseMapInfo<char> {
}
};
// Provide DenseMapInfo for unsigned chars.
template <> struct DenseMapInfo<unsigned char> {
static inline unsigned char getEmptyKey() { return ~0; }
static inline unsigned char getTombstoneKey() { return ~0 - 1; }
static unsigned getHashValue(const unsigned char &Val) { return Val * 37U; }
static bool isEqual(const unsigned char &LHS, const unsigned char &RHS) {
return LHS == RHS;
}
};
// Provide DenseMapInfo for unsigned shorts.
template <> struct DenseMapInfo<unsigned short> {
static inline unsigned short getEmptyKey() { return 0xFFFF; }
@@ -187,17 +222,8 @@ struct DenseMapInfo<std::pair<T, U>> {
}
static unsigned getHashValue(const Pair& PairVal) {
uint64_t key = (uint64_t)FirstInfo::getHashValue(PairVal.first) << 32
| (uint64_t)SecondInfo::getHashValue(PairVal.second);
key += ~(key << 32);
key ^= (key >> 22);
key += ~(key << 13);
key ^= (key >> 8);
key += (key << 3);
key ^= (key >> 15);
key += ~(key << 27);
key ^= (key >> 31);
return (unsigned)key;
return detail::combineHashValue(FirstInfo::getHashValue(PairVal.first),
SecondInfo::getHashValue(PairVal.second));
}
static bool isEqual(const Pair &LHS, const Pair &RHS) {
@@ -206,59 +232,53 @@ struct DenseMapInfo<std::pair<T, U>> {
}
};
// Provide DenseMapInfo for std::string_view.
template <> struct DenseMapInfo<std::string_view> {
static inline std::string_view getEmptyKey() {
return std::string_view(reinterpret_cast<const char *>(~static_cast<uintptr_t>(0)),
0);
// Provide DenseMapInfo for all tuples whose members have info.
template <typename... Ts> struct DenseMapInfo<std::tuple<Ts...>> {
using Tuple = std::tuple<Ts...>;
static inline Tuple getEmptyKey() {
return Tuple(DenseMapInfo<Ts>::getEmptyKey()...);
}
static inline std::string_view getTombstoneKey() {
return std::string_view(reinterpret_cast<const char *>(~static_cast<uintptr_t>(1)),
0);
static inline Tuple getTombstoneKey() {
return Tuple(DenseMapInfo<Ts>::getTombstoneKey()...);
}
static unsigned getHashValue(std::string_view 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));
template <unsigned I>
static unsigned getHashValueImpl(const Tuple &values, std::false_type) {
using EltType = typename std::tuple_element<I, Tuple>::type;
std::integral_constant<bool, I + 1 == sizeof...(Ts)> atEnd;
return detail::combineHashValue(
DenseMapInfo<EltType>::getHashValue(std::get<I>(values)),
getHashValueImpl<I + 1>(values, atEnd));
}
static bool isEqual(std::string_view LHS, std::string_view RHS) {
if (RHS.data() == getEmptyKey().data())
return LHS.data() == getEmptyKey().data();
if (RHS.data() == getTombstoneKey().data())
return LHS.data() == getTombstoneKey().data();
return LHS == RHS;
}
};
// Provide DenseMapInfo for spans.
template <typename T> struct DenseMapInfo<span<T>> {
static inline span<T> getEmptyKey() {
return span<T>(reinterpret_cast<const T *>(~static_cast<uintptr_t>(0)),
size_t(0));
template <unsigned I>
static unsigned getHashValueImpl(const Tuple &, std::true_type) {
return 0;
}
static inline span<T> getTombstoneKey() {
return span<T>(reinterpret_cast<const T *>(~static_cast<uintptr_t>(1)),
size_t(0));
static unsigned getHashValue(const std::tuple<Ts...> &values) {
std::integral_constant<bool, 0 == sizeof...(Ts)> atEnd;
return getHashValueImpl<0>(values, atEnd);
}
static unsigned getHashValue(span<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));
template <unsigned I>
static bool isEqualImpl(const Tuple &lhs, const Tuple &rhs, std::false_type) {
using EltType = typename std::tuple_element<I, Tuple>::type;
std::integral_constant<bool, I + 1 == sizeof...(Ts)> atEnd;
return DenseMapInfo<EltType>::isEqual(std::get<I>(lhs), std::get<I>(rhs)) &&
isEqualImpl<I + 1>(lhs, rhs, atEnd);
}
static bool isEqual(span<T> LHS, span<T> RHS) {
if (RHS.data() == getEmptyKey().data())
return LHS.data() == getEmptyKey().data();
if (RHS.data() == getTombstoneKey().data())
return LHS.data() == getTombstoneKey().data();
return LHS == RHS;
template <unsigned I>
static bool isEqualImpl(const Tuple &, const Tuple &, std::true_type) {
return true;
}
static bool isEqual(const Tuple &lhs, const Tuple &rhs) {
std::integral_constant<bool, 0 == sizeof...(Ts)> atEnd;
return isEqualImpl<0>(lhs, rhs, atEnd);
}
};
@@ -271,4 +291,4 @@ template <> struct DenseMapInfo<hash_code> {
} // end namespace wpi
#endif // LLVM_ADT_DENSEMAPINFO_H
#endif // WPIUTIL_WPI_DENSEMAPINFO_H

View File

@@ -1,9 +1,8 @@
//===- Endian.h - Utilities for IO with endian specific data ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -14,14 +13,8 @@
#ifndef WPIUTIL_WPI_ENDIAN_H
#define WPIUTIL_WPI_ENDIAN_H
#include "wpi/AlignOf.h"
#include "wpi/Compiler.h"
#include "wpi/SwapByteOrder.h"
#if defined(__linux__) || defined(__GNU__)
#include <endian.h>
#endif
#include <cassert>
#include <cstddef>
#include <cstdint>
@@ -38,7 +31,7 @@ enum {aligned = 0, unaligned = 1};
namespace detail {
// value is either alignment, or alignof(T) if alignment is 0.
/// ::value is either alignment, or alignof(T) if alignment is 0.
template<class T, int alignment>
struct PickAlignment {
enum { value = alignment == 0 ? alignof(T) : alignment };
@@ -49,13 +42,7 @@ struct PickAlignment {
namespace endian {
constexpr endianness system_endianness() {
#ifdef _WIN32
return little;
#elif defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && __BYTE_ORDER == __BIG_ENDIAN
return big;
#else
return little;
#endif
return sys::IsBigEndianHost ? big : little;
}
template <typename value_type>
@@ -89,13 +76,7 @@ template<typename value_type,
endianness endian,
std::size_t alignment>
inline value_type read(const void *memory) {
value_type ret;
memcpy(&ret,
LLVM_ASSUME_ALIGNED(
memory, (detail::PickAlignment<value_type, alignment>::value)),
sizeof(value_type));
return byte_swap<value_type, endian>(ret);
return read<value_type, alignment>(memory, endian);
}
/// Read a value of a particular endianness from a buffer, and increment the
@@ -110,9 +91,7 @@ inline value_type readNext(const CharT *&memory, endianness endian) {
template<typename value_type, endianness endian, std::size_t alignment,
typename CharT>
inline value_type readNext(const CharT *&memory) {
value_type ret = read<value_type, endian, alignment>(memory);
memory += sizeof(value_type);
return ret;
return readNext<value_type, alignment, CharT>(memory, endian);
}
/// Write a value to memory with a particular endianness.
@@ -128,12 +107,12 @@ template<typename value_type,
endianness endian,
std::size_t alignment>
inline void write(void *memory, value_type value) {
value = byte_swap<value_type, endian>(value);
memcpy(LLVM_ASSUME_ALIGNED(
memory, (detail::PickAlignment<value_type, alignment>::value)),
&value, sizeof(value_type));
write<value_type, alignment>(memory, value, endian);
}
template <typename value_type>
using make_unsigned_t = std::make_unsigned_t<value_type>;
/// Read a value of a particular endianness from memory, for a location
/// that starts at the given bit offset within the first byte.
template <typename value_type, endianness endian, std::size_t alignment>
@@ -152,15 +131,15 @@ inline value_type readAtBitAlignment(const void *memory, uint64_t startBit) {
val[1] = byte_swap<value_type, endian>(val[1]);
// Shift bits from the lower value into place.
std::make_unsigned_t<value_type> lowerVal = val[0] >> startBit;
make_unsigned_t<value_type> lowerVal = val[0] >> startBit;
// Mask off upper bits after right shift in case of signed type.
std::make_unsigned_t<value_type> numBitsFirstVal =
make_unsigned_t<value_type> numBitsFirstVal =
(sizeof(value_type) * 8) - startBit;
lowerVal &= ((std::make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1;
lowerVal &= ((make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1;
// Get the bits from the upper value.
std::make_unsigned_t<value_type> upperVal =
val[1] & (((std::make_unsigned_t<value_type>)1 << startBit) - 1);
make_unsigned_t<value_type> upperVal =
val[1] & (((make_unsigned_t<value_type>)1 << startBit) - 1);
// Shift them in to place.
upperVal <<= numBitsFirstVal;
@@ -188,15 +167,15 @@ inline void writeAtBitAlignment(void *memory, value_type value,
// Mask off any existing bits in the upper part of the lower value that
// we want to replace.
val[0] &= ((std::make_unsigned_t<value_type>)1 << startBit) - 1;
std::make_unsigned_t<value_type> numBitsFirstVal =
val[0] &= ((make_unsigned_t<value_type>)1 << startBit) - 1;
make_unsigned_t<value_type> numBitsFirstVal =
(sizeof(value_type) * 8) - startBit;
std::make_unsigned_t<value_type> lowerVal = value;
make_unsigned_t<value_type> lowerVal = value;
if (startBit > 0) {
// Mask off the upper bits in the new value that are not going to go into
// the lower value. This avoids a left shift of a negative value, which
// is undefined behavior.
lowerVal &= (((std::make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1);
lowerVal &= (((make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1);
// Now shift the new bits into place
lowerVal <<= startBit;
}
@@ -204,11 +183,11 @@ inline void writeAtBitAlignment(void *memory, value_type value,
// Mask off any existing bits in the lower part of the upper value that
// we want to replace.
val[1] &= ~(((std::make_unsigned_t<value_type>)1 << startBit) - 1);
val[1] &= ~(((make_unsigned_t<value_type>)1 << startBit) - 1);
// Next shift the bits that go into the upper value into position.
std::make_unsigned_t<value_type> upperVal = value >> numBitsFirstVal;
make_unsigned_t<value_type> upperVal = value >> numBitsFirstVal;
// Mask off upper bits after right shift in case of signed type.
upperVal &= ((std::make_unsigned_t<value_type>)1 << startBit) - 1;
upperVal &= ((make_unsigned_t<value_type>)1 << startBit) - 1;
val[1] |= upperVal;
// Finally, rewrite values.
@@ -224,10 +203,13 @@ inline void writeAtBitAlignment(void *memory, value_type value,
namespace detail {
template<typename value_type,
endianness endian,
std::size_t alignment>
template <typename ValueType, endianness Endian, std::size_t Alignment,
std::size_t ALIGN = PickAlignment<ValueType, Alignment>::value>
struct packed_endian_specific_integral {
using value_type = ValueType;
static constexpr endianness endian = Endian;
static constexpr std::size_t alignment = Alignment;
packed_endian_specific_integral() = default;
explicit packed_endian_specific_integral(value_type val) { *this = val; }
@@ -263,8 +245,9 @@ struct packed_endian_specific_integral {
}
private:
AlignedCharArray<PickAlignment<value_type, alignment>::value,
sizeof(value_type)> Value;
struct {
alignas(ALIGN) char buffer[sizeof(value_type)];
} Value;
public:
struct ref {
@@ -355,6 +338,17 @@ using unaligned_int32_t =
using unaligned_int64_t =
detail::packed_endian_specific_integral<int64_t, native, unaligned>;
template <typename T>
using little_t = detail::packed_endian_specific_integral<T, little, unaligned>;
template <typename T>
using big_t = detail::packed_endian_specific_integral<T, big, unaligned>;
template <typename T>
using aligned_little_t =
detail::packed_endian_specific_integral<T, little, aligned>;
template <typename T>
using aligned_big_t = detail::packed_endian_specific_integral<T, big, aligned>;
namespace endian {
template <typename T> inline T read(const void *P, endianness E) {

View File

@@ -1,9 +1,8 @@
//===- llvm/ADT/EpochTracker.h - ADT epoch tracking --------------*- C++ -*-==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -13,29 +12,15 @@
//
//===----------------------------------------------------------------------===//
#ifndef WPIUTIL_WPI_EPOCH_TRACKER_H
#define WPIUTIL_WPI_EPOCH_TRACKER_H
#ifndef WPIUTIL_WPI_EPOCHTRACKER_H
#define WPIUTIL_WPI_EPOCHTRACKER_H
#include <cstdint>
namespace wpi {
#ifdef NDEBUG //ifndef LLVM_ENABLE_ABI_BREAKING_CHECKS
class DebugEpochBase {
public:
void incrementEpoch() {}
class HandleBase {
public:
HandleBase() = default;
explicit HandleBase(const DebugEpochBase *) {}
bool isHandleInSync() const { return true; }
const void *getEpochAddress() const { return nullptr; }
};
};
#else
#ifndef NDEBUG //ifndef LLVM_ENABLE_ABI_BREAKING_CHECKS
/// A base class for data structure classes wishing to make iterators
/// ("handles") pointing into themselves fail-fast. When building without
@@ -90,6 +75,21 @@ public:
};
};
#else
class DebugEpochBase {
public:
void incrementEpoch() {}
class HandleBase {
public:
HandleBase() = default;
explicit HandleBase(const DebugEpochBase *) {}
bool isHandleInSync() const { return true; }
const void *getEpochAddress() const { return nullptr; }
};
};
#endif // LLVM_ENABLE_ABI_BREAKING_CHECKS
} // namespace wpi

View File

@@ -1,9 +1,8 @@
//===- llvm/Support/Errc.h - Defines the llvm::errc enum --------*- C++ -*-===//
//===- llvm/Support/Errc.h - Defines the wpi::errc enum --------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -11,7 +10,7 @@
// some problems with std::errc that can be avoided by using our own
// enumeration:
//
// * std::errc is a namespace in some implementations. That meas that ADL
// * std::errc is a namespace in some implementations. That means that ADL
// doesn't work and it is sometimes necessary to write std::make_error_code
// or in templates:
// using std::make_error_code;
@@ -23,7 +22,7 @@
// the intersection of all the ones we support.
//
// * std::errc is just marked with is_error_condition_enum. This means that
// common patters like AnErrorCode == errc::no_such_file_or_directory take
// common patterns like AnErrorCode == errc::no_such_file_or_directory take
// 4 virtual calls instead of two comparisons.
//===----------------------------------------------------------------------===//

View File

@@ -1,9 +1,8 @@
//===- llvm/Support/Errno.h - Portable+convenient errno handling -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -22,8 +21,8 @@ namespace wpi {
namespace sys {
template <typename FailT, typename Fun, typename... Args>
inline auto RetryAfterSignal(const FailT &Fail, const Fun &F,
const Args &... As) -> decltype(F(As...)) {
inline decltype(auto) RetryAfterSignal(const FailT &Fail, const Fun &F,
const Args &... As) {
decltype(F(As...)) Res;
do {
errno = 0;
@@ -35,4 +34,4 @@ inline auto RetryAfterSignal(const FailT &Fail, const Fun &F,
} // namespace sys
} // namespace wpi
#endif // WPIUTIL_WPI_ERRNO_H
#endif // WPIUTIL_WPI_ERRNO_H

View File

@@ -1,9 +1,8 @@
//===- llvm/Support/ErrorHandling.h - Fatal error handling ------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -20,6 +19,7 @@
#include <string_view>
namespace wpi {
/// An error handler callback.
typedef void (*fatal_error_handler_t)(void *user_data,
const std::string& reason,
@@ -65,7 +65,7 @@ namespace wpi {
///
/// If no error handler is installed the default is to print the message to
/// standard error, followed by a newline.
/// After the error handler is called this function will call exit(1), it
/// After the error handler is called this function will call abort(), it
/// does not return.
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(const char *reason,
bool gen_crash_diag = true);
@@ -100,31 +100,32 @@ void install_out_of_memory_new_handler();
/// Reports a bad alloc error, calling any user defined bad alloc
/// error handler. In contrast to the generic 'report_fatal_error'
/// functions, this function is expected to return, e.g. the user
/// defined error handler throws an exception.
/// functions, this function might not terminate, e.g. the user
/// defined error handler throws an exception, but it won't return.
///
/// Note: When throwing an exception in the bad alloc handler, make sure that
/// the following unwind succeeds, e.g. do not trigger additional allocations
/// in the unwind chain.
///
/// If no error handler is installed (default), then a bad_alloc exception
/// is thrown, if LLVM is compiled with exception support, otherwise an
/// assertion is called.
void report_bad_alloc_error(const char *Reason, bool GenCrashDiag = true);
/// If no error handler is installed (default), throws a bad_alloc exception
/// if LLVM is compiled with exception support. Otherwise prints the error
/// to standard error and calls abort().
LLVM_ATTRIBUTE_NORETURN void report_bad_alloc_error(const char *Reason,
bool GenCrashDiag = true);
/// This function calls abort(), and prints the optional message to stderr.
/// Use the wpi_unreachable macro (that adds location info), instead of
/// calling this function directly.
LLVM_ATTRIBUTE_NORETURN void
wpi_unreachable_internal(const char *msg = nullptr, const char *file = nullptr,
unsigned line = 0);
unsigned line = 0);
}
/// Marks that the current location is not supposed to be reachable.
/// In !NDEBUG builds, prints the message and location info to stderr.
/// In NDEBUG builds, becomes an optimizer hint that the current location
/// is not supposed to be reachable. On compilers that don't support
/// such hints, prints a reduced message instead.
/// such hints, prints a reduced message instead and aborts the program.
///
/// Use this instead of assert(0). It conveys intent more clearly and
/// allows compilers to omit some unnecessary code.

View File

@@ -1,9 +1,8 @@
//===- FunctionExtras.h - Function type erasure utilities -------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
@@ -12,11 +11,11 @@
/// in `<function>`.
///
/// It provides `unique_function`, which works like `std::function` but supports
/// move-only callable objects.
/// move-only callable objects and const-qualification.
///
/// Future plans:
/// - Add a `function` that provides const, volatile, and ref-qualified support,
/// which doesn't work with `std::function`.
/// - Add a `function` that provides ref-qualified support, which doesn't work
/// with `std::function`.
/// - Provide support for specifying multiple signatures to type erase callable
/// objects with an overload set, such as those produced by generic lambdas.
/// - Expand to include a copyable utility that directly replaces std::function
@@ -30,17 +29,29 @@
///
//===----------------------------------------------------------------------===//
#ifndef WPIUTIL_WPI_FUNCTION_EXTRAS_H
#define WPIUTIL_WPI_FUNCTION_EXTRAS_H
#ifndef WPIUTIL_WPI_FUNCTIONEXTRAS_H
#define WPIUTIL_WPI_FUNCTIONEXTRAS_H
#include "wpi/Compiler.h"
#include "wpi/PointerIntPair.h"
#include "wpi/PointerUnion.h"
#include "wpi/STLForwardCompat.h"
#include "wpi/MemAlloc.h"
#include "wpi/type_traits.h"
#include <memory>
#include <type_traits>
namespace wpi {
/// unique_function is a type-erasing functor similar to std::function.
///
/// It can hold move-only function objects, like lambdas capturing unique_ptrs.
/// Accordingly, it is movable but not copyable.
///
/// It supports const-qualification:
/// - unique_function<int() const> has a const operator().
/// It can only hold functions which themselves have a const operator().
/// - unique_function<int()> has a non-const operator().
/// It can hold functions with a non-const operator(), like mutable lambdas.
template <typename FunctionT> class unique_function;
// GCC warns on OutOfLineStorage
@@ -49,16 +60,32 @@ template <typename FunctionT> class unique_function;
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
template <typename ReturnT, typename... ParamTs>
class unique_function<ReturnT(ParamTs...)> {
namespace detail {
template <typename T>
using EnableIfTrivial =
std::enable_if_t<wpi::is_trivially_move_constructible<T>::value &&
std::is_trivially_destructible<T>::value>;
template <typename CallableT, typename ThisT>
using EnableUnlessSameType =
std::enable_if_t<!std::is_same<remove_cvref_t<CallableT>, ThisT>::value>;
template <typename CallableT, typename Ret, typename... Params>
using EnableIfCallable =
std::enable_if_t<std::is_void<Ret>::value ||
std::is_convertible<decltype(std::declval<CallableT>()(
std::declval<Params>()...)),
Ret>::value>;
template <typename ReturnT, typename... ParamTs> class UniqueFunctionBase {
protected:
static constexpr size_t InlineStorageSize = sizeof(void *) * 4;
// MSVC has a bug and ICEs if we give it a particular dependent value
// expression as part of the `std::conditional` below. To work around this,
// we build that into a template struct's constexpr bool.
template <typename T> struct IsSizeLessThanThresholdT {
static constexpr bool value = sizeof(T) <= (2 * sizeof(void *));
};
template <typename T, class = void>
struct IsSizeLessThanThresholdT : std::false_type {};
template <typename T>
struct IsSizeLessThanThresholdT<
T, std::enable_if_t<sizeof(T) <= 2 * sizeof(void *)>> : std::true_type {};
// Provide a type function to map parameters that won't observe extra copies
// or moves and which are small enough to likely pass in register to values
@@ -69,13 +96,24 @@ class unique_function<ReturnT(ParamTs...)> {
// The heuristic used is related to common ABI register passing conventions.
// It doesn't have to be exact though, and in one way it is more strict
// because we want to still be able to observe either moves *or* copies.
template <typename T> struct AdjustedParamTBase {
static_assert(!std::is_reference<T>::value,
"references should be handled by template specialization");
using type = typename std::conditional<
wpi::is_trivially_copy_constructible<T>::value &&
wpi::is_trivially_move_constructible<T>::value &&
IsSizeLessThanThresholdT<T>::value,
T, T &>::type;
};
// This specialization ensures that 'AdjustedParam<V<T>&>' or
// 'AdjustedParam<V<T>&&>' does not trigger a compile-time error when 'T' is
// an incomplete type and V a templated type.
template <typename T> struct AdjustedParamTBase<T &> { using type = T &; };
template <typename T> struct AdjustedParamTBase<T &&> { using type = T &; };
template <typename T>
using AdjustedParamT = typename std::conditional<
!std::is_reference<T>::value &&
std::is_trivially_copy_constructible<T>::value &&
std::is_trivially_move_constructible<T>::value &&
IsSizeLessThanThresholdT<T>::value,
T, T &>::type;
using AdjustedParamT = typename AdjustedParamTBase<T>::type;
// The type of the erased function pointer we use as a callback to dispatch to
// the stored callable when it is trivial to move and destroy.
@@ -120,8 +158,11 @@ class unique_function<ReturnT(ParamTs...)> {
// For in-line storage, we just provide an aligned character buffer. We
// provide four pointers worth of storage here.
typename std::aligned_storage<InlineStorageSize, alignof(void *)>::type
InlineStorage;
// This is mutable as an inlined `const unique_function<void() const>` may
// still modify its own mutable members.
mutable
typename std::aligned_storage<InlineStorageSize, alignof(void *)>::type
InlineStorage;
} StorageUnion;
// A compressed pointer to either our dispatching callback or our table of
@@ -144,11 +185,25 @@ class unique_function<ReturnT(ParamTs...)> {
.template get<NonTrivialCallbacks *>();
}
void *getInlineStorage() { return &StorageUnion.InlineStorage; }
CallPtrT getCallPtr() const {
return isTrivialCallback() ? getTrivialCallback()
: getNonTrivialCallbacks()->CallPtr;
}
void *getOutOfLineStorage() {
// These three functions are only const in the narrow sense. They return
// mutable pointers to function state.
// This allows unique_function<T const>::operator() to be const, even if the
// underlying functor may be internally mutable.
//
// const callers must ensure they're only used in const-correct ways.
void *getCalleePtr() const {
return isInlineStorage() ? getInlineStorage() : getOutOfLineStorage();
}
void *getInlineStorage() const { return &StorageUnion.InlineStorage; }
void *getOutOfLineStorage() const {
return StorageUnion.OutOfLineStorage.StoragePtr;
}
size_t getOutOfLineStorageSize() const {
return StorageUnion.OutOfLineStorage.Size;
}
@@ -160,10 +215,11 @@ class unique_function<ReturnT(ParamTs...)> {
StorageUnion.OutOfLineStorage = {Ptr, Size, Alignment};
}
template <typename CallableT>
static ReturnT CallImpl(void *CallableAddr, AdjustedParamT<ParamTs>... Params) {
return (*reinterpret_cast<CallableT *>(CallableAddr))(
std::forward<ParamTs>(Params)...);
template <typename CalledAsT>
static ReturnT CallImpl(void *CallableAddr,
AdjustedParamT<ParamTs>... Params) {
auto &Func = *reinterpret_cast<CalledAsT *>(CallableAddr);
return Func(std::forward<ParamTs>(Params)...);
}
template <typename CallableT>
@@ -177,11 +233,54 @@ class unique_function<ReturnT(ParamTs...)> {
reinterpret_cast<CallableT *>(CallableAddr)->~CallableT();
}
public:
unique_function() = default;
unique_function(std::nullptr_t /*null_callable*/) {}
// The pointers to call/move/destroy functions are determined for each
// callable type (and called-as type, which determines the overload chosen).
// (definitions are out-of-line).
~unique_function() {
// By default, we need an object that contains all the different
// type erased behaviors needed. Create a static instance of the struct type
// here and each instance will contain a pointer to it.
// Wrap in a struct to avoid https://gcc.gnu.org/PR71954
template <typename CallableT, typename CalledAs, typename Enable = void>
struct CallbacksHolder {
static NonTrivialCallbacks Callbacks;
};
// See if we can create a trivial callback. We need the callable to be
// trivially moved and trivially destroyed so that we don't have to store
// type erased callbacks for those operations.
template <typename CallableT, typename CalledAs>
struct CallbacksHolder<CallableT, CalledAs, EnableIfTrivial<CallableT>> {
static TrivialCallback Callbacks;
};
// A simple tag type so the call-as type to be passed to the constructor.
template <typename T> struct CalledAs {};
// Essentially the "main" unique_function constructor, but subclasses
// provide the qualified type to be used for the call.
// (We always store a T, even if the call will use a pointer to const T).
template <typename CallableT, typename CalledAsT>
UniqueFunctionBase(CallableT Callable, CalledAs<CalledAsT>) {
bool IsInlineStorage = true;
void *CallableAddr = getInlineStorage();
if (sizeof(CallableT) > InlineStorageSize ||
alignof(CallableT) > alignof(decltype(StorageUnion.InlineStorage))) {
IsInlineStorage = false;
// Allocate out-of-line storage. FIXME: Use an explicit alignment
// parameter in C++17 mode.
auto Size = sizeof(CallableT);
auto Alignment = alignof(CallableT);
CallableAddr = allocate_buffer(Size, Alignment);
setOutOfLineStorage(CallableAddr, Size, Alignment);
}
// Now move into the storage.
new (CallableAddr) CallableT(std::move(Callable));
CallbackAndInlineFlag.setPointerAndInt(
&CallbacksHolder<CallableT, CalledAsT>::Callbacks, IsInlineStorage);
}
~UniqueFunctionBase() {
if (!CallbackAndInlineFlag.getPointer())
return;
@@ -197,7 +296,7 @@ public:
getOutOfLineStorageAlignment());
}
unique_function(unique_function &&RHS) noexcept {
UniqueFunctionBase(UniqueFunctionBase &&RHS) noexcept {
// Copy the callback and inline flag.
CallbackAndInlineFlag = RHS.CallbackAndInlineFlag;
@@ -226,83 +325,96 @@ public:
#endif
}
unique_function &operator=(unique_function &&RHS) noexcept {
UniqueFunctionBase &operator=(UniqueFunctionBase &&RHS) noexcept {
if (this == &RHS)
return *this;
// Because we don't try to provide any exception safety guarantees we can
// implement move assignment very simply by first destroying the current
// object and then move-constructing over top of it.
this->~unique_function();
new (this) unique_function(std::move(RHS));
this->~UniqueFunctionBase();
new (this) UniqueFunctionBase(std::move(RHS));
return *this;
}
template <typename CallableT>
unique_function(CallableT Callable,
std::enable_if_t<
std::is_invocable_r_v<
ReturnT, CallableT, ParamTs...>>* = nullptr) {
bool IsInlineStorage = true;
void *CallableAddr = getInlineStorage();
if (sizeof(CallableT) > InlineStorageSize ||
alignof(CallableT) > alignof(decltype(StorageUnion.InlineStorage))) {
IsInlineStorage = false;
// Allocate out-of-line storage. FIXME: Use an explicit alignment
// parameter in C++17 mode.
auto Size = sizeof(CallableT);
auto Alignment = alignof(CallableT);
CallableAddr = allocate_buffer(Size, Alignment);
setOutOfLineStorage(CallableAddr, Size, Alignment);
}
// Now move into the storage.
new (CallableAddr) CallableT(std::move(Callable));
// See if we can create a trivial callback. We need the callable to be
// trivially moved and trivially destroyed so that we don't have to store
// type erased callbacks for those operations.
//
// FIXME: We should use constexpr if here and below to avoid instantiating
// the non-trivial static objects when unnecessary. While the linker should
// remove them, it is still wasteful.
if (std::is_trivially_move_constructible<CallableT>::value &&
std::is_trivially_destructible<CallableT>::value) {
// We need to create a nicely aligned object. We use a static variable
// for this because it is a trivial struct.
static TrivialCallback Callback = { &CallImpl<CallableT> };
CallbackAndInlineFlag = {&Callback, IsInlineStorage};
return;
}
// Otherwise, we need to point at an object that contains all the different
// type erased behaviors needed. Create a static instance of the struct type
// here and then use a pointer to that.
static NonTrivialCallbacks Callbacks = {
&CallImpl<CallableT>, &MoveImpl<CallableT>, &DestroyImpl<CallableT>};
CallbackAndInlineFlag = {&Callbacks, IsInlineStorage};
}
ReturnT operator()(ParamTs... Params) {
void *CallableAddr =
isInlineStorage() ? getInlineStorage() : getOutOfLineStorage();
return (isTrivialCallback()
? getTrivialCallback()
: getNonTrivialCallbacks()->CallPtr)(CallableAddr, Params...);
}
UniqueFunctionBase() = default;
public:
explicit operator bool() const {
return (bool)CallbackAndInlineFlag.getPointer();
}
};
template <typename R, typename... P>
template <typename CallableT, typename CalledAsT, typename Enable>
typename UniqueFunctionBase<R, P...>::NonTrivialCallbacks UniqueFunctionBase<
R, P...>::CallbacksHolder<CallableT, CalledAsT, Enable>::Callbacks = {
&CallImpl<CalledAsT>, &MoveImpl<CallableT>, &DestroyImpl<CallableT>};
template <typename R, typename... P>
template <typename CallableT, typename CalledAsT>
typename UniqueFunctionBase<R, P...>::TrivialCallback
UniqueFunctionBase<R, P...>::CallbacksHolder<
CallableT, CalledAsT, EnableIfTrivial<CallableT>>::Callbacks{
&CallImpl<CalledAsT>};
} // namespace detail
template <typename R, typename... P>
class unique_function<R(P...)> : public detail::UniqueFunctionBase<R, P...> {
using Base = detail::UniqueFunctionBase<R, P...>;
public:
unique_function() = default;
unique_function(std::nullptr_t) {}
unique_function(unique_function &&) = default;
unique_function(const unique_function &) = delete;
unique_function &operator=(unique_function &&) = default;
unique_function &operator=(const unique_function &) = delete;
template <typename CallableT>
unique_function(
CallableT Callable,
detail::EnableUnlessSameType<CallableT, unique_function> * = nullptr,
detail::EnableIfCallable<CallableT, R, P...> * = nullptr)
: Base(std::forward<CallableT>(Callable),
typename Base::template CalledAs<CallableT>{}) {}
R operator()(P... Params) {
return this->getCallPtr()(this->getCalleePtr(), Params...);
}
};
template <typename R, typename... P>
class unique_function<R(P...) const>
: public detail::UniqueFunctionBase<R, P...> {
using Base = detail::UniqueFunctionBase<R, P...>;
public:
unique_function() = default;
unique_function(std::nullptr_t) {}
unique_function(unique_function &&) = default;
unique_function(const unique_function &) = delete;
unique_function &operator=(unique_function &&) = default;
unique_function &operator=(const unique_function &) = delete;
template <typename CallableT>
unique_function(
CallableT Callable,
detail::EnableUnlessSameType<CallableT, unique_function> * = nullptr,
detail::EnableIfCallable<const CallableT, R, P...> * = nullptr)
: Base(std::forward<CallableT>(Callable),
typename Base::template CalledAs<const CallableT>{}) {}
R operator()(P... Params) const {
return this->getCallPtr()(this->getCalleePtr(), Params...);
}
};
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
} // end namespace wpi
#endif // WPIUTIL_WPI_FUNCTION_H
#endif // WPIUTIL_WPI_FUNCTIONEXTRAS_H

View File

@@ -1,9 +1,8 @@
//===-- llvm/ADT/Hashing.h - Utilities for hashing --------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -45,15 +44,14 @@
#ifndef WPIUTIL_WPI_HASHING_H
#define WPIUTIL_WPI_HASHING_H
#include "wpi/Endian.h"
#include "wpi/ErrorHandling.h"
#include "wpi/SwapByteOrder.h"
#include "wpi/type_traits.h"
#include <stdint.h>
#include <algorithm>
#include <cassert>
#include <cstring>
#include <string>
#include <string_view>
#include <tuple>
#include <utility>
#ifdef _WIN32
@@ -108,8 +106,7 @@ public:
/// differing argument types even if they would implicit promote to a common
/// type without changing the value.
template <typename T>
typename std::enable_if<is_integral_or_enum<T>::value, hash_code>::type
hash_value(T value);
std::enable_if_t<is_integral_or_enum<T>::value, hash_code> hash_value(T value);
/// Compute a hash_code for a pointer's address.
///
@@ -120,6 +117,10 @@ template <typename T> hash_code hash_value(const T *ptr);
template <typename T, typename U>
hash_code hash_value(const std::pair<T, U> &arg);
/// Compute a hash_code for a tuple.
template <typename... Ts>
hash_code hash_value(const std::tuple<Ts...> &arg);
/// Compute a hash_code for a standard string.
template <typename T>
hash_code hash_value(const std::basic_string<T> &arg);
@@ -151,7 +152,7 @@ namespace detail {
inline uint64_t fetch64(const char *p) {
uint64_t result;
memcpy(&result, p, sizeof(result));
if (support::endian::system_endianness() == support::big)
if (sys::IsBigEndianHost)
sys::swapByteOrder(result);
return result;
}
@@ -159,16 +160,16 @@ inline uint64_t fetch64(const char *p) {
inline uint32_t fetch32(const char *p) {
uint32_t result;
memcpy(&result, p, sizeof(result));
if (support::endian::system_endianness() == support::big)
if (sys::IsBigEndianHost)
sys::swapByteOrder(result);
return result;
}
/// Some primes between 2^63 and 2^64 for various uses.
static const uint64_t k0 = 0xc3a5c85c97cb3127ULL;
static const uint64_t k1 = 0xb492b66fbe98f273ULL;
static const uint64_t k2 = 0x9ae16a3b2f90404fULL;
static const uint64_t k3 = 0xc949d7c7509e6557ULL;
static constexpr uint64_t k0 = 0xc3a5c85c97cb3127ULL;
static constexpr uint64_t k1 = 0xb492b66fbe98f273ULL;
static constexpr uint64_t k2 = 0x9ae16a3b2f90404fULL;
static constexpr uint64_t k3 = 0xc949d7c7509e6557ULL;
/// Bitwise right rotate.
/// Normally this will compile to a single instruction, especially if the
@@ -198,7 +199,7 @@ inline uint64_t hash_1to3_bytes(const char *s, size_t len, uint64_t seed) {
uint8_t b = s[len >> 1];
uint8_t c = s[len - 1];
uint32_t y = static_cast<uint32_t>(a) + (static_cast<uint32_t>(b) << 8);
uint32_t z = static_cast<uint32_t>(len + (static_cast<uint64_t>(c) << 2));
uint32_t z = static_cast<uint32_t>(len) + (static_cast<uint32_t>(c) << 2);
return shift_mix(y * k2 ^ z * k3 ^ seed) * k2;
}
@@ -264,7 +265,7 @@ inline uint64_t hash_short(const char *s, size_t length, uint64_t seed) {
/// 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;
uint64_t h0 = 0, h1 = 0, h2 = 0, h3 = 0, h4 = 0, h5 = 0, h6 = 0;
/// Create a new hash_state structure and initialize it based on the
/// seed and the first 64-byte chunk.
@@ -367,7 +368,7 @@ template <typename T, typename U> struct is_hashable_data<std::pair<T, U> >
/// 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
std::enable_if_t<is_hashable_data<T>::value, T>
get_hashable_data(const T &value) {
return value;
}
@@ -375,7 +376,7 @@ get_hashable_data(const T &value) {
/// This variant is enabled when we must first call hash_value and use the
/// result as our data.
template <typename T>
typename std::enable_if<!is_hashable_data<T>::value, size_t>::type
std::enable_if_t<!is_hashable_data<T>::value, size_t>
get_hashable_data(const T &value) {
using ::wpi::hash_value;
return hash_value(value);
@@ -449,7 +450,7 @@ hash_code hash_combine_range_impl(InputIteratorT first, InputIteratorT last) {
/// are stored in contiguous memory, this routine avoids copying each value
/// and directly reads from the underlying memory.
template <typename ValueT>
typename std::enable_if<is_hashable_data<ValueT>::value, hash_code>::type
std::enable_if_t<is_hashable_data<ValueT>::value, hash_code>
hash_combine_range_impl(ValueT *first, ValueT *last) {
const uint64_t seed = get_execution_seed();
const char *s_begin = reinterpret_cast<const char *>(first);
@@ -499,7 +500,7 @@ namespace detail {
/// useful at minimizing the code in the recursive calls to ease the pain
/// caused by a lack of variadic functions.
struct hash_combine_recursive_helper {
char buffer[64];
char buffer[64] = {};
hash_state state;
const uint64_t seed;
@@ -547,7 +548,7 @@ public:
// store types smaller than the buffer.
if (!store_and_advance(buffer_ptr, buffer_end, data,
partial_store_size))
abort();
wpi_unreachable("buffer smaller than stored type");
}
return buffer_ptr;
}
@@ -574,7 +575,7 @@ public:
// Check whether the entire set of values fit in the buffer. If so, we'll
// use the optimized short hashing routine and skip state entirely.
if (length == 0)
return static_cast<size_t>(hash_short(buffer, buffer_ptr - buffer, seed));
return hash_short(buffer, buffer_ptr - buffer, seed);
// Mix the final buffer, rotating it if we did a partial fill in order to
// simulate doing a mix of the last 64-bytes. That is how the algorithm
@@ -586,7 +587,7 @@ public:
state.mix(buffer);
length += buffer_ptr - buffer;
return static_cast<size_t>(state.finalize(length));
return state.finalize(length);
}
};
@@ -625,7 +626,7 @@ inline hash_code hash_integer_value(uint64_t value) {
const uint64_t seed = get_execution_seed();
const char *s = reinterpret_cast<const char *>(&value);
const uint64_t a = fetch32(s);
return static_cast<size_t>(hash_16_bytes(seed + (a << 3), fetch32(s + 4)));
return hash_16_bytes(seed + (a << 3), fetch32(s + 4));
}
} // namespace detail
@@ -634,8 +635,7 @@ inline hash_code hash_integer_value(uint64_t value) {
// Declared and documented above, but defined here so that any of the hashing
// infrastructure is available.
template <typename T>
typename std::enable_if<is_integral_or_enum<T>::value, hash_code>::type
hash_value(T value) {
std::enable_if_t<is_integral_or_enum<T>::value, hash_code> hash_value(T value) {
return ::wpi::hashing::detail::hash_integer_value(
static_cast<uint64_t>(value));
}
@@ -654,6 +654,26 @@ hash_code hash_value(const std::pair<T, U> &arg) {
return hash_combine(arg.first, arg.second);
}
// Implementation details for the hash_value overload for std::tuple<...>(...).
namespace hashing {
namespace detail {
template <typename... Ts, std::size_t... Indices>
hash_code hash_value_tuple_helper(const std::tuple<Ts...> &arg,
std::index_sequence<Indices...>) {
return hash_combine(std::get<Indices>(arg)...);
}
} // namespace detail
} // namespace hashing
template <typename... Ts>
hash_code hash_value(const std::tuple<Ts...> &arg) {
// TODO: Use std::apply when LLVM starts using C++17.
return ::wpi::hashing::detail::hash_value_tuple_helper(
arg, typename std::index_sequence_for<Ts...>());
}
// Declared and documented above, but defined here so that any of the hashing
// infrastructure is available.
template <typename T>
@@ -661,11 +681,6 @@ hash_code hash_value(const std::basic_string<T> &arg) {
return hash_combine_range(arg.begin(), arg.end());
}
template <typename T>
hash_code hash_value(const std::basic_string_view<T> &arg) {
return hash_combine_range(arg.begin(), arg.end());
}
} // namespace wpi
#ifdef _WIN32

View File

@@ -1,9 +1,8 @@
//===-- llvm/Support/ManagedStatic.h - Static Global wrapper ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -33,19 +32,41 @@ template <typename T, size_t N> struct object_deleter<T[N]> {
static void call(void *Ptr) { delete[](T *)Ptr; }
};
// ManagedStatic must be initialized to zero, and it must *not* have a dynamic
// initializer because managed statics are often created while running other
// dynamic initializers. In standard C++11, the best way to accomplish this is
// with a constexpr default constructor. However, different versions of the
// Visual C++ compiler have had bugs where, even though the constructor may be
// constexpr, a dynamic initializer may be emitted depending on optimization
// settings. For the affected versions of MSVC, use the old linker
// initialization pattern of not providing a constructor and leaving the fields
// uninitialized. See http://llvm.org/PR41367 for details.
#if !defined(_MSC_VER) || (_MSC_VER >= 1925) || defined(__clang__)
#define LLVM_USE_CONSTEXPR_CTOR
#endif
/// ManagedStaticBase - Common base class for ManagedStatic instances.
class ManagedStaticBase {
protected:
#ifdef LLVM_USE_CONSTEXPR_CTOR
mutable std::atomic<void *> Ptr{};
mutable void (*DeleterFn)(void *) = nullptr;
mutable const ManagedStaticBase *Next = nullptr;
#else
// This should only be used as a static variable, which guarantees that this
// will be zero initialized.
mutable std::atomic<void *> Ptr;
mutable void (*DeleterFn)(void*);
mutable void (*DeleterFn)(void *);
mutable const ManagedStaticBase *Next;
#endif
void RegisterManagedStatic(void *(*creator)(), void (*deleter)(void*)) const;
void RegisterManagedStatic(void *created, void (*deleter)(void*)) const;
public:
#ifdef LLVM_USE_CONSTEXPR_CTOR
constexpr ManagedStaticBase() = default;
#endif
/// isConstructed - Return true if this object has not been created yet.
bool isConstructed() const { return Ptr != nullptr; }
@@ -61,12 +82,6 @@ template <class C, class Creator = object_creator<C>,
class Deleter = object_deleter<C>>
class ManagedStatic : public ManagedStaticBase {
public:
ManagedStatic() = default;
ManagedStatic(C* created, void(*deleter)(void*)) {
RegisterManagedStatic(created, deleter);
}
// Accessors.
C &operator*() {
void *Tmp = Ptr.load(std::memory_order_acquire);
@@ -87,6 +102,12 @@ public:
}
const C *operator->() const { return &**this; }
// Extract the instance, leaving the ManagedStatic uninitialized. The
// user is then responsible for the lifetime of the returned instance.
C *claim() {
return static_cast<C *>(Ptr.exchange(nullptr));
}
};
/// wpi_shutdown - Deallocate and destroy all ManagedStatic variables.

View File

@@ -1,9 +1,8 @@
//===- llvm/ADT/MapVector.h - Map w/ deterministic value order --*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -237,4 +236,4 @@ struct SmallMapVector
} // end namespace wpi
#endif // LLVM_ADT_MAPVECTOR_H
#endif // WPIUTIL_WPI_MAPVECTOR_H

View File

@@ -1,9 +1,8 @@
//===-- llvm/Support/MathExtras.h - Useful math functions -------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -15,15 +14,18 @@
#define WPIUTIL_WPI_MATHEXTRAS_H
#include "wpi/Compiler.h"
#include <cstdint>
#include <algorithm>
#include <cassert>
#include <climits>
#include <cmath>
#include <cstdint>
#include <cstring>
#include <limits>
#include <type_traits>
#ifdef __ANDROID_NDK__
#include <android/api-level.h>
#endif
#ifdef _MSC_VER
// Declare these intrinsics manually rather including intrin.h. It's very
// expensive, and MathExtras.h is popular.
@@ -37,6 +39,7 @@ unsigned char _BitScanReverse64(unsigned long *_Index, unsigned __int64 _Mask);
#endif
namespace wpi {
/// The behavior an operation has on an input of 0.
enum ZeroBehavior {
/// The returned value is undefined.
@@ -49,14 +52,14 @@ enum ZeroBehavior {
namespace detail {
template <typename T, std::size_t SizeOfT> struct TrailingZerosCounter {
static std::size_t count(T Val, ZeroBehavior) {
static unsigned count(T Val, ZeroBehavior) {
if (!Val)
return std::numeric_limits<T>::digits;
if (Val & 0x1)
return 0;
// Bisection method.
std::size_t ZeroBits = 0;
unsigned ZeroBits = 0;
T Shift = std::numeric_limits<T>::digits >> 1;
T Mask = (std::numeric_limits<T>::max)() >> Shift;
while (Shift) {
@@ -71,13 +74,13 @@ template <typename T, std::size_t SizeOfT> struct TrailingZerosCounter {
}
};
#if __GNUC__ >= 4 || defined(_MSC_VER)
#if defined(__GNUC__) || defined(_MSC_VER)
template <typename T> struct TrailingZerosCounter<T, 4> {
static std::size_t count(T Val, ZeroBehavior ZB) {
static unsigned count(T Val, ZeroBehavior ZB) {
if (ZB != ZB_Undefined && Val == 0)
return 32;
#if __has_builtin(__builtin_ctz) || LLVM_GNUC_PREREQ(4, 0, 0)
#if __has_builtin(__builtin_ctz) || defined(__GNUC__)
return __builtin_ctz(Val);
#elif defined(_MSC_VER)
unsigned long Index;
@@ -89,11 +92,11 @@ template <typename T> struct TrailingZerosCounter<T, 4> {
#if !defined(_MSC_VER) || defined(_M_X64)
template <typename T> struct TrailingZerosCounter<T, 8> {
static std::size_t count(T Val, ZeroBehavior ZB) {
static unsigned count(T Val, ZeroBehavior ZB) {
if (ZB != ZB_Undefined && Val == 0)
return 64;
#if __has_builtin(__builtin_ctzll) || LLVM_GNUC_PREREQ(4, 0, 0)
#if __has_builtin(__builtin_ctzll) || defined(__GNUC__)
return __builtin_ctzll(Val);
#elif defined(_MSC_VER)
unsigned long Index;
@@ -114,7 +117,7 @@ template <typename T> struct TrailingZerosCounter<T, 8> {
/// \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) {
unsigned 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.");
@@ -123,12 +126,12 @@ std::size_t countTrailingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
namespace detail {
template <typename T, std::size_t SizeOfT> struct LeadingZerosCounter {
static std::size_t count(T Val, ZeroBehavior) {
static unsigned count(T Val, ZeroBehavior) {
if (!Val)
return std::numeric_limits<T>::digits;
// Bisection method.
std::size_t ZeroBits = 0;
unsigned ZeroBits = 0;
for (T Shift = std::numeric_limits<T>::digits >> 1; Shift; Shift >>= 1) {
T Tmp = Val >> Shift;
if (Tmp)
@@ -140,13 +143,13 @@ template <typename T, std::size_t SizeOfT> struct LeadingZerosCounter {
}
};
#if __GNUC__ >= 4 || defined(_MSC_VER)
#if defined(__GNUC__) || defined(_MSC_VER)
template <typename T> struct LeadingZerosCounter<T, 4> {
static std::size_t count(T Val, ZeroBehavior ZB) {
static unsigned count(T Val, ZeroBehavior ZB) {
if (ZB != ZB_Undefined && Val == 0)
return 32;
#if __has_builtin(__builtin_clz) || LLVM_GNUC_PREREQ(4, 0, 0)
#if __has_builtin(__builtin_clz) || defined(__GNUC__)
return __builtin_clz(Val);
#elif defined(_MSC_VER)
unsigned long Index;
@@ -158,11 +161,11 @@ template <typename T> struct LeadingZerosCounter<T, 4> {
#if !defined(_MSC_VER) || defined(_M_X64)
template <typename T> struct LeadingZerosCounter<T, 8> {
static std::size_t count(T Val, ZeroBehavior ZB) {
static unsigned count(T Val, ZeroBehavior ZB) {
if (ZB != ZB_Undefined && Val == 0)
return 64;
#if __has_builtin(__builtin_clzll) || LLVM_GNUC_PREREQ(4, 0, 0)
#if __has_builtin(__builtin_clzll) || defined(__GNUC__)
return __builtin_clzll(Val);
#elif defined(_MSC_VER)
unsigned long Index;
@@ -183,7 +186,7 @@ template <typename T> struct LeadingZerosCounter<T, 8> {
/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are
/// valid arguments.
template <typename T>
std::size_t countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
unsigned 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.");
@@ -273,6 +276,34 @@ T reverseBits(T Val) {
return Val;
}
#if __has_builtin(__builtin_bitreverse8)
template<>
inline uint8_t reverseBits<uint8_t>(uint8_t Val) {
return __builtin_bitreverse8(Val);
}
#endif
#if __has_builtin(__builtin_bitreverse16)
template<>
inline uint16_t reverseBits<uint16_t>(uint16_t Val) {
return __builtin_bitreverse16(Val);
}
#endif
#if __has_builtin(__builtin_bitreverse32)
template<>
inline uint32_t reverseBits<uint32_t>(uint32_t Val) {
return __builtin_bitreverse32(Val);
}
#endif
#if __has_builtin(__builtin_bitreverse64)
template<>
inline uint64_t reverseBits<uint64_t>(uint64_t Val) {
return __builtin_bitreverse64(Val);
}
#endif
// NOTE: The following support functions use the _32/_64 extensions instead of
// type overloading so that signed and unsigned integers can be used without
// ambiguity.
@@ -325,14 +356,12 @@ constexpr inline bool isShiftedInt(int64_t x) {
/// 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) {
constexpr inline std::enable_if_t<(N < 64), bool> 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) {
constexpr inline std::enable_if_t<N >= 64, bool> isUInt(uint64_t) {
return true;
}
@@ -379,7 +408,7 @@ inline uint64_t maxUIntN(uint64_t N) {
inline int64_t minIntN(int64_t N) {
assert(N > 0 && N <= 64 && "integer width out of range");
return -(UINT64_C(1)<<(N-1));
return UINT64_C(1) + ~(UINT64_C(1) << (N - 1));
}
#ifdef _WIN32
@@ -450,7 +479,7 @@ constexpr inline bool isPowerOf2_64(uint64_t Value) {
/// \param ZB the behavior on an input of all ones. Only ZB_Width and
/// ZB_Undefined are valid arguments.
template <typename T>
std::size_t countLeadingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
unsigned 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.");
@@ -466,7 +495,7 @@ std::size_t countLeadingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
/// \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) {
unsigned 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.");
@@ -478,7 +507,7 @@ template <typename T, std::size_t SizeOfT> struct PopulationCounter {
static unsigned count(T Value) {
// Generic version, forward to 32 bits.
static_assert(SizeOfT <= 4, "Not implemented!");
#if __GNUC__ >= 4
#if defined(__GNUC__)
return __builtin_popcount(Value);
#else
uint32_t v = Value;
@@ -491,7 +520,7 @@ template <typename T, std::size_t SizeOfT> struct PopulationCounter {
template <typename T> struct PopulationCounter<T, 8> {
static unsigned count(T Value) {
#if __GNUC__ >= 4
#if defined(__GNUC__)
return __builtin_popcountll(Value);
#else
uint64_t v = Value;
@@ -515,6 +544,16 @@ inline unsigned countPopulation(T Value) {
return detail::PopulationCounter<T, sizeof(T)>::count(Value);
}
/// Compile time Log2.
/// Valid only for positive powers of two.
template <size_t kValue> constexpr inline size_t CTLog2() {
static_assert(kValue > 0 && wpi::isPowerOf2_64(kValue),
"Value is not a valid power of 2");
return 1 + CTLog2<kValue / 2>();
}
template <> constexpr inline size_t CTLog2<1>() { return 0; }
/// Return the log base 2 of the specified value.
inline double Log2(double Value) {
#if defined(__ANDROID_API__) && __ANDROID_API__ < 18
@@ -551,15 +590,20 @@ inline unsigned Log2_64_Ceil(uint64_t Value) {
}
/// Return the greatest common divisor of the values using Euclid's algorithm.
inline uint64_t GreatestCommonDivisor64(uint64_t A, uint64_t B) {
template <typename T>
inline T greatestCommonDivisor(T A, T B) {
while (B) {
uint64_t T = B;
T Tmp = B;
B = A % B;
A = T;
A = Tmp;
}
return A;
}
inline uint64_t GreatestCommonDivisor64(uint64_t A, uint64_t B) {
return greatestCommonDivisor<uint64_t>(A, B);
}
/// This function takes a 64-bit integer and returns the bit equivalent double.
inline double BitsToDouble(uint64_t Bits) {
double D;
@@ -607,25 +651,6 @@ constexpr inline uint64_t MinAlign(uint64_t A, uint64_t B) {
return (A | B) & (1 + ~(A | B));
}
/// Aligns \c Addr to \c Alignment bytes, rounding up.
///
/// Alignment should be a power of two. This method rounds up, so
/// alignAddr(7, 4) == 8 and alignAddr(8, 4) == 8.
inline uintptr_t alignAddr(const void *Addr, size_t Alignment) {
assert(Alignment && isPowerOf2_64((uint64_t)Alignment) &&
"Alignment is not a power of two!");
assert((uintptr_t)Addr + Alignment - 1 >= (uintptr_t)Addr);
return (((uintptr_t)Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1));
}
/// 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;
}
/// 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) {
@@ -691,18 +716,10 @@ 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 integer nearest(Numerator / Denominator).
inline uint64_t divideNearest(uint64_t Numerator, uint64_t Denominator) {
return (Numerator + (Denominator / 2)) / Denominator;
}
/// 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
@@ -712,13 +729,6 @@ inline uint64_t alignDown(uint64_t Value, uint64_t Align, uint64_t Skew = 0) {
return (Value - Skew) / Align * Align + Skew;
}
/// Returns the offset to the next integer (mod 2**64) that is greater than
/// or equal to \p Value and is a multiple of \p Align. \p Align must be
/// non-zero.
inline uint64_t OffsetToAlignment(uint64_t Value, uint64_t Align) {
return alignTo(Value, Align) - Value;
}
/// Sign-extend the number in the bottom B bits of X to a 32-bit integer.
/// Requires 0 < B <= 32.
template <unsigned B> constexpr inline int32_t SignExtend32(uint32_t X) {
@@ -728,7 +738,7 @@ template <unsigned B> constexpr inline int32_t SignExtend32(uint32_t X) {
}
/// Sign-extend the number in the bottom B bits of X to a 32-bit integer.
/// Requires 0 < B < 32.
/// 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.");
@@ -736,7 +746,7 @@ inline int32_t SignExtend32(uint32_t X, unsigned B) {
}
/// Sign-extend the number in the bottom B bits of X to a 64-bit integer.
/// Requires 0 < B < 64.
/// 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.");
@@ -744,7 +754,7 @@ template <unsigned B> constexpr inline int64_t SignExtend64(uint64_t x) {
}
/// Sign-extend the number in the bottom B bits of X to a 64-bit integer.
/// Requires 0 < B < 64.
/// 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.");
@@ -754,16 +764,15 @@ inline int64_t SignExtend64(uint64_t X, unsigned B) {
/// 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);
std::enable_if_t<std::is_unsigned<T>::value, T> AbsoluteDifference(T X, T Y) {
return X > Y ? (X - Y) : (Y - X);
}
/// 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
std::enable_if_t<std::is_unsigned<T>::value, T>
SaturatingAdd(T X, T Y, bool *ResultOverflowed = nullptr) {
bool Dummy;
bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
@@ -780,7 +789,7 @@ SaturatingAdd(T X, T Y, bool *ResultOverflowed = nullptr) {
/// 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
std::enable_if_t<std::is_unsigned<T>::value, T>
SaturatingMultiply(T X, T Y, bool *ResultOverflowed = nullptr) {
bool Dummy;
bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
@@ -826,7 +835,7 @@ SaturatingMultiply(T X, T Y, bool *ResultOverflowed = nullptr) {
/// 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
std::enable_if_t<std::is_unsigned<T>::value, T>
SaturatingMultiplyAdd(T X, T Y, T A, bool *ResultOverflowed = nullptr) {
bool Dummy;
bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
@@ -838,6 +847,89 @@ SaturatingMultiplyAdd(T X, T Y, T A, bool *ResultOverflowed = nullptr) {
return SaturatingAdd(A, Product, &Overflowed);
}
/// Use this rather than HUGE_VALF; the latter causes warnings on MSVC.
extern const float huge_valf;
/// Add two signed integers, computing the two's complement truncated result,
/// returning true if overflow occured.
template <typename T>
std::enable_if_t<std::is_signed<T>::value, T> AddOverflow(T X, T Y, T &Result) {
#if __has_builtin(__builtin_add_overflow)
return __builtin_add_overflow(X, Y, &Result);
#else
// Perform the unsigned addition.
using U = std::make_unsigned_t<T>;
const U UX = static_cast<U>(X);
const U UY = static_cast<U>(Y);
const U UResult = UX + UY;
// Convert to signed.
Result = static_cast<T>(UResult);
// Adding two positive numbers should result in a positive number.
if (X > 0 && Y > 0)
return Result <= 0;
// Adding two negatives should result in a negative number.
if (X < 0 && Y < 0)
return Result >= 0;
return false;
#endif
}
/// Subtract two signed integers, computing the two's complement truncated
/// result, returning true if an overflow ocurred.
template <typename T>
std::enable_if_t<std::is_signed<T>::value, T> SubOverflow(T X, T Y, T &Result) {
#if __has_builtin(__builtin_sub_overflow)
return __builtin_sub_overflow(X, Y, &Result);
#else
// Perform the unsigned addition.
using U = std::make_unsigned_t<T>;
const U UX = static_cast<U>(X);
const U UY = static_cast<U>(Y);
const U UResult = UX - UY;
// Convert to signed.
Result = static_cast<T>(UResult);
// Subtracting a positive number from a negative results in a negative number.
if (X <= 0 && Y > 0)
return Result >= 0;
// Subtracting a negative number from a positive results in a positive number.
if (X >= 0 && Y < 0)
return Result <= 0;
return false;
#endif
}
/// Multiply two signed integers, computing the two's complement truncated
/// result, returning true if an overflow ocurred.
template <typename T>
std::enable_if_t<std::is_signed<T>::value, T> MulOverflow(T X, T Y, T &Result) {
// Perform the unsigned multiplication on absolute values.
using U = std::make_unsigned_t<T>;
const U UX = X < 0 ? (0 - static_cast<U>(X)) : static_cast<U>(X);
const U UY = Y < 0 ? (0 - static_cast<U>(Y)) : static_cast<U>(Y);
const U UResult = UX * UY;
// Convert to signed.
const bool IsNegative = (X < 0) ^ (Y < 0);
Result = IsNegative ? (0 - UResult) : UResult;
// If any of the args was 0, result is 0 and no overflow occurs.
if (UX == 0 || UY == 0)
return false;
// UX and UY are in [1, 2^n], where n is the number of digits.
// Check how the max allowed absolute value (2^n for negative, 2^(n-1) for
// positive) divided by an argument compares to the other.
if (IsNegative)
return UX > (static_cast<U>((std::numeric_limits<T>::max)()) + U(1)) / UY;
else
return UX > (static_cast<U>((std::numeric_limits<T>::max)())) / UY;
}
// Typesafe implementation of the signum function.
// Returns -1 if negative, 1 if positive, 0 if 0.
template <typename T>
@@ -858,7 +950,6 @@ template <typename T>
constexpr T Lerp(const T& startValue, const T& endValue, double t) {
return startValue + (endValue - startValue) * t;
}
} // namespace wpi
} // End wpi namespace
#endif

View File

@@ -1,9 +1,8 @@
//===- MemAlloc.h - Memory allocation functions -----------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
@@ -33,29 +32,69 @@ namespace wpi {
LLVM_ATTRIBUTE_RETURNS_NONNULL inline void *safe_malloc(size_t Sz) {
void *Result = std::malloc(Sz);
if (Result == nullptr)
if (Result == nullptr) {
// It is implementation-defined whether allocation occurs if the space
// requested is zero (ISO/IEC 9899:2018 7.22.3). Retry, requesting
// non-zero, if the space requested was zero.
if (Sz == 0)
return safe_malloc(1);
report_bad_alloc_error("Allocation failed");
}
return Result;
}
LLVM_ATTRIBUTE_RETURNS_NONNULL inline void *safe_calloc(size_t Count,
size_t Sz) {
void *Result = std::calloc(Count, Sz);
if (Result == nullptr)
if (Result == nullptr) {
// It is implementation-defined whether allocation occurs if the space
// requested is zero (ISO/IEC 9899:2018 7.22.3). Retry, requesting
// non-zero, if the space requested was zero.
if (Count == 0 || Sz == 0)
return safe_malloc(1);
report_bad_alloc_error("Allocation failed");
}
return Result;
}
LLVM_ATTRIBUTE_RETURNS_NONNULL inline void *safe_realloc(void *Ptr, size_t Sz) {
void *Result = std::realloc(Ptr, Sz);
if (Result == nullptr)
if (Result == nullptr) {
// It is implementation-defined whether allocation occurs if the space
// requested is zero (ISO/IEC 9899:2018 7.22.3). Retry, requesting
// non-zero, if the space requested was zero.
if (Sz == 0)
return safe_malloc(1);
report_bad_alloc_error("Allocation failed");
}
return Result;
}
/// Allocate a buffer of memory with the given size and alignment.
///
/// When the compiler supports aligned operator new, this will use it to to
/// handle even over-aligned allocations.
///
/// However, this doesn't make any attempt to leverage the fancier techniques
/// like posix_memalign due to portability. It is mostly intended to allow
/// compatibility with platforms that, after aligned allocation was added, use
/// reduced default alignment.
LLVM_ATTRIBUTE_RETURNS_NONNULL LLVM_ATTRIBUTE_RETURNS_NOALIAS void *
allocate_buffer(size_t Size, size_t Alignment);
/// Deallocate a buffer of memory with the given size and alignment.
///
/// If supported, this will used the sized delete operator. Also if supported,
/// this will pass the alignment to the delete operator.
///
/// The pointer must have been allocated with the corresponding new operator,
/// most likely using the above helper.
void deallocate_buffer(void *Ptr, size_t Size, size_t Alignment);
} // namespace wpi
#ifdef _WIN32
#pragma warning(pop)
#endif
}
#endif

View File

@@ -1,9 +1,8 @@
//===- llvm/ADT/PointerIntPair.h - Pair for pointer and int -----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -14,7 +13,9 @@
#ifndef WPIUTIL_WPI_POINTERINTPAIR_H
#define WPIUTIL_WPI_POINTERINTPAIR_H
#include "wpi/Compiler.h"
#include "wpi/PointerLikeTypeTraits.h"
#include "wpi/type_traits.h"
#include <cassert>
#include <cstdint>
#include <limits>
@@ -59,19 +60,19 @@ public:
IntType getInt() const { return (IntType)Info::getInt(Value); }
void setPointer(PointerTy PtrVal) {
void setPointer(PointerTy PtrVal) LLVM_LVALUE_FUNCTION {
Value = Info::updatePointer(Value, PtrVal);
}
void setInt(IntType IntVal) {
void setInt(IntType IntVal) LLVM_LVALUE_FUNCTION {
Value = Info::updateInt(Value, static_cast<intptr_t>(IntVal));
}
void initWithPointer(PointerTy PtrVal) {
void initWithPointer(PointerTy PtrVal) LLVM_LVALUE_FUNCTION {
Value = Info::updatePointer(0, PtrVal);
}
void setPointerAndInt(PointerTy PtrVal, IntType IntVal) {
void setPointerAndInt(PointerTy PtrVal, IntType IntVal) LLVM_LVALUE_FUNCTION {
Value = Info::updateInt(Info::updatePointer(0, PtrVal),
static_cast<intptr_t>(IntVal));
}
@@ -89,7 +90,7 @@ public:
void *getOpaqueValue() const { return reinterpret_cast<void *>(Value); }
void setFromOpaqueValue(void *Val) {
void setFromOpaqueValue(void *Val) LLVM_LVALUE_FUNCTION {
Value = reinterpret_cast<intptr_t>(Val);
}
@@ -126,6 +127,7 @@ public:
}
};
template <typename PointerT, unsigned IntBits, typename PtrTraits>
struct PointerIntPairInfo {
static_assert(PtrTraits::NumLowBitsAvailable <
@@ -133,7 +135,7 @@ struct PointerIntPairInfo {
"cannot use a pointer type that has all bits free");
static_assert(IntBits <= PtrTraits::NumLowBitsAvailable,
"PointerIntPair with integer size too large for pointer");
enum : uintptr_t {
enum MaskAndShiftConstants : uintptr_t {
/// PointerBitMask - The bits that come from the pointer.
PointerBitMask =
~(uintptr_t)(((intptr_t)1 << PtrTraits::NumLowBitsAvailable) - 1),
@@ -176,12 +178,6 @@ struct PointerIntPairInfo {
}
};
template <typename T> struct isPodLike;
template <typename PointerTy, unsigned IntBits, typename IntType>
struct isPodLike<PointerIntPair<PointerTy, IntBits, IntType>> {
static const bool value = true;
};
// Provide specialization of DenseMapInfo for PointerIntPair.
template <typename PointerTy, unsigned IntBits, typename IntType>
struct DenseMapInfo<PointerIntPair<PointerTy, IntBits, IntType>> {
@@ -227,7 +223,8 @@ struct PointerLikeTypeTraits<
return PointerIntPair<PointerTy, IntBits, IntType>::getFromOpaqueValue(P);
}
enum { NumLowBitsAvailable = PtrTraits::NumLowBitsAvailable - IntBits };
static constexpr int NumLowBitsAvailable =
PtrTraits::NumLowBitsAvailable - IntBits;
};
} // end namespace wpi

View File

@@ -1,9 +1,8 @@
//===- llvm/Support/PointerLikeTypeTraits.h - Pointer Traits ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -15,8 +14,8 @@
#ifndef WPIUTIL_WPI_POINTERLIKETYPETRAITS_H
#define WPIUTIL_WPI_POINTERLIKETYPETRAITS_H
#include <cassert>
#include <cstdint>
#include <cstdlib>
#include <type_traits>
namespace wpi {
@@ -38,8 +37,9 @@ template <typename T, typename U = void> struct HasPointerLikeTypeTraits {
};
// sizeof(T) is valid only for a complete T.
template <typename T> struct HasPointerLikeTypeTraits<
T, decltype((sizeof(PointerLikeTypeTraits<T>) + sizeof(T)), void())> {
template <typename T>
struct HasPointerLikeTypeTraits<
T, decltype((sizeof(PointerLikeTypeTraits<T>) + sizeof(T)), void())> {
static const bool value = true;
};
@@ -57,7 +57,8 @@ 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)>::value };
static constexpr int NumLowBitsAvailable =
detail::ConstantLog2<alignof(T)>::value;
};
template <> struct PointerLikeTypeTraits<void *> {
@@ -71,7 +72,7 @@ template <> struct PointerLikeTypeTraits<void *> {
///
/// All clients should use assertions to do a run-time check to ensure that
/// this is actually true.
enum { NumLowBitsAvailable = 2 };
static constexpr int NumLowBitsAvailable = 2;
};
// Provide PointerLikeTypeTraits for const things.
@@ -84,7 +85,7 @@ template <typename T> struct PointerLikeTypeTraits<const T> {
static inline const T getFromVoidPointer(const void *P) {
return NonConst::getFromVoidPointer(const_cast<void *>(P));
}
enum { NumLowBitsAvailable = NonConst::NumLowBitsAvailable };
static constexpr int NumLowBitsAvailable = NonConst::NumLowBitsAvailable;
};
// Provide PointerLikeTypeTraits for const pointers.
@@ -97,7 +98,7 @@ template <typename T> struct PointerLikeTypeTraits<const T *> {
static inline const T *getFromVoidPointer(const void *P) {
return NonConst::getFromVoidPointer(const_cast<void *>(P));
}
enum { NumLowBitsAvailable = NonConst::NumLowBitsAvailable };
static constexpr int NumLowBitsAvailable = NonConst::NumLowBitsAvailable;
};
// Provide PointerLikeTypeTraits for uintptr_t.
@@ -109,7 +110,7 @@ template <> struct PointerLikeTypeTraits<uintptr_t> {
return reinterpret_cast<uintptr_t>(P);
}
// No bits are available!
enum { NumLowBitsAvailable = 0 };
static constexpr int NumLowBitsAvailable = 0;
};
/// Provide suitable custom traits struct for function pointers.
@@ -122,7 +123,8 @@ template <> struct PointerLikeTypeTraits<uintptr_t> {
/// potentially use alignment attributes on functions to satisfy that.
template <int Alignment, typename FunctionPointerT>
struct FunctionPointerLikeTypeTraits {
enum { NumLowBitsAvailable = detail::ConstantLog2<Alignment>::value };
static constexpr int NumLowBitsAvailable =
detail::ConstantLog2<Alignment>::value;
static inline void *getAsVoidPointer(FunctionPointerT P) {
assert((reinterpret_cast<uintptr_t>(P) &
~((uintptr_t)-1 << NumLowBitsAvailable)) == 0 &&

View File

@@ -1,9 +1,8 @@
//===- llvm/ADT/PointerUnion.h - Discriminated Union of 2 Ptrs --*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -54,22 +53,84 @@ struct PointerUnionTypeSelectorReturn<
typename PointerUnionTypeSelector<T1, T2, RET_EQ, RET_NE>::Return;
};
/// Provide PointerLikeTypeTraits for void* that is used by PointerUnion
/// for the two template arguments.
template <typename PT1, typename PT2> class PointerUnionUIntTraits {
public:
static inline void *getAsVoidPointer(void *P) { return P; }
static inline void *getFromVoidPointer(void *P) { return P; }
namespace pointer_union_detail {
/// Determine the number of bits required to store integers with values < n.
/// This is ceil(log2(n)).
constexpr int bitsRequired(unsigned n) {
return n > 1 ? 1 + bitsRequired((n + 1) / 2) : 0;
}
enum {
PT1BitsAv = (int)(PointerLikeTypeTraits<PT1>::NumLowBitsAvailable),
PT2BitsAv = (int)(PointerLikeTypeTraits<PT2>::NumLowBitsAvailable),
NumLowBitsAvailable = PT1BitsAv < PT2BitsAv ? PT1BitsAv : PT2BitsAv
template <typename... Ts> constexpr int lowBitsAvailable() {
return std::min<int>({PointerLikeTypeTraits<Ts>::NumLowBitsAvailable...});
}
/// Find the index of a type in a list of types. TypeIndex<T, Us...>::Index
/// is the index of T in Us, or sizeof...(Us) if T does not appear in the
/// list.
template <typename T, typename ...Us> struct TypeIndex;
template <typename T, typename ...Us> struct TypeIndex<T, T, Us...> {
static constexpr int Index = 0;
};
template <typename T, typename U, typename... Us>
struct TypeIndex<T, U, Us...> {
static constexpr int Index = 1 + TypeIndex<T, Us...>::Index;
};
template <typename T> struct TypeIndex<T> {
static constexpr int Index = 0;
};
};
/// A discriminated union of two pointer types, with the discriminator in the
/// low bit of the pointer.
/// Find the first type in a list of types.
template <typename T, typename...> struct GetFirstType {
using type = T;
};
/// Provide PointerLikeTypeTraits for void* that is used by PointerUnion
/// for the template arguments.
template <typename ...PTs> class PointerUnionUIntTraits {
public:
static inline void *getAsVoidPointer(void *P) { return P; }
static inline void *getFromVoidPointer(void *P) { return P; }
static constexpr int NumLowBitsAvailable = lowBitsAvailable<PTs...>();
};
template <typename Derived, typename ValTy, int I, typename ...Types>
class PointerUnionMembers;
template <typename Derived, typename ValTy, int I>
class PointerUnionMembers<Derived, ValTy, I> {
protected:
ValTy Val;
PointerUnionMembers() = default;
PointerUnionMembers(ValTy Val) : Val(Val) {}
friend struct PointerLikeTypeTraits<Derived>;
};
template <typename Derived, typename ValTy, int I, typename Type,
typename ...Types>
class PointerUnionMembers<Derived, ValTy, I, Type, Types...>
: public PointerUnionMembers<Derived, ValTy, I + 1, Types...> {
using Base = PointerUnionMembers<Derived, ValTy, I + 1, Types...>;
public:
using Base::Base;
PointerUnionMembers() = default;
PointerUnionMembers(Type V)
: Base(ValTy(const_cast<void *>(
PointerLikeTypeTraits<Type>::getAsVoidPointer(V)),
I)) {}
using Base::operator=;
Derived &operator=(Type V) {
this->Val = ValTy(
const_cast<void *>(PointerLikeTypeTraits<Type>::getAsVoidPointer(V)),
I);
return static_cast<Derived &>(*this);
};
};
}
/// A discriminated union of two or more pointer types, with the discriminator
/// in the low bit of the pointer.
///
/// This implementation is extremely efficient in space due to leveraging the
/// low bits of the pointer, while exposing a natural and type-safe API.
@@ -84,49 +145,40 @@ public:
/// P = (float*)0;
/// Y = P.get<float*>(); // ok.
/// X = P.get<int*>(); // runtime assertion failure.
template <typename PT1, typename PT2> class PointerUnion {
public:
using ValTy =
PointerIntPair<void *, 1, bool, PointerUnionUIntTraits<PT1, PT2>>;
private:
ValTy Val;
struct IsPT1 {
static const int Num = 0;
};
struct IsPT2 {
static const int Num = 1;
};
template <typename T> struct UNION_DOESNT_CONTAIN_TYPE {};
template <typename... PTs>
class PointerUnion
: public pointer_union_detail::PointerUnionMembers<
PointerUnion<PTs...>,
PointerIntPair<
void *, pointer_union_detail::bitsRequired(sizeof...(PTs)), int,
pointer_union_detail::PointerUnionUIntTraits<PTs...>>,
0, PTs...> {
// The first type is special because we want to directly cast a pointer to a
// default-initialized union to a pointer to the first type. But we don't
// want PointerUnion to be a 'template <typename First, typename ...Rest>'
// because it's much more convenient to have a name for the whole pack. So
// split off the first type here.
using First = typename pointer_union_detail::GetFirstType<PTs...>::type;
using Base = typename PointerUnion::PointerUnionMembers;
public:
PointerUnion() = default;
PointerUnion(PT1 V)
: Val(const_cast<void *>(
PointerLikeTypeTraits<PT1>::getAsVoidPointer(V))) {}
PointerUnion(PT2 V)
: Val(const_cast<void *>(PointerLikeTypeTraits<PT2>::getAsVoidPointer(V)),
1) {}
PointerUnion(std::nullptr_t) : PointerUnion() {}
using Base::Base;
/// Test if the pointer held in the union is null, regardless of
/// which type it is.
bool isNull() const {
// Convert from the void* to one of the pointer types, to make sure that
// we recursively strip off low bits if we have a nested PointerUnion.
return !PointerLikeTypeTraits<PT1>::getFromVoidPointer(Val.getPointer());
}
bool isNull() const { return !this->Val.getPointer(); }
explicit operator bool() const { return !isNull(); }
/// Test if the Union currently holds the type matching T.
template <typename T> int is() const {
using Ty = typename ::wpi::PointerUnionTypeSelector<
PT1, T, IsPT1,
::wpi::PointerUnionTypeSelector<PT2, T, IsPT2,
UNION_DOESNT_CONTAIN_TYPE<T>>>::Return;
int TyNo = Ty::Num;
return static_cast<int>(Val.getInt()) == TyNo;
template <typename T> bool is() const {
constexpr int Index = pointer_union_detail::TypeIndex<T, PTs...>::Index;
static_assert(Index < sizeof...(PTs),
"PointerUnion::is<T> given type not in the union");
return this->Val.getInt() == Index;
}
/// Returns the value of the specified pointer type.
@@ -134,11 +186,11 @@ public:
/// If the specified pointer type is incorrect, assert.
template <typename T> T get() const {
assert(is<T>() && "Invalid accessor called");
return PointerLikeTypeTraits<T>::getFromVoidPointer(Val.getPointer());
return PointerLikeTypeTraits<T>::getFromVoidPointer(this->Val.getPointer());
}
/// Returns the current pointer if it is of the specified pointer type,
/// otherwises returns null.
/// otherwise returns null.
template <typename T> T dyn_cast() const {
if (is<T>())
return get<T>();
@@ -147,342 +199,91 @@ public:
/// If the union is set to the first pointer type get an address pointing to
/// it.
PT1 const *getAddrOfPtr1() const {
First const *getAddrOfPtr1() const {
return const_cast<PointerUnion *>(this)->getAddrOfPtr1();
}
/// If the union is set to the first pointer type get an address pointing to
/// it.
PT1 *getAddrOfPtr1() {
assert(is<PT1>() && "Val is not the first pointer");
First *getAddrOfPtr1() {
assert(is<First>() && "Val is not the first pointer");
assert(
get<PT1>() == Val.getPointer() &&
PointerLikeTypeTraits<First>::getAsVoidPointer(get<First>()) ==
this->Val.getPointer() &&
"Can't get the address because PointerLikeTypeTraits changes the ptr");
return const_cast<PT1 *>(
reinterpret_cast<const PT1 *>(Val.getAddrOfPointer()));
return const_cast<First *>(
reinterpret_cast<const First *>(this->Val.getAddrOfPointer()));
}
/// Assignment from nullptr which just clears the union.
const PointerUnion &operator=(std::nullptr_t) {
Val.initWithPointer(nullptr);
this->Val.initWithPointer(nullptr);
return *this;
}
/// Assignment operators - Allow assigning into this union from either
/// pointer type, setting the discriminator to remember what it came from.
const PointerUnion &operator=(const PT1 &RHS) {
Val.initWithPointer(
const_cast<void *>(PointerLikeTypeTraits<PT1>::getAsVoidPointer(RHS)));
return *this;
}
const PointerUnion &operator=(const PT2 &RHS) {
Val.setPointerAndInt(
const_cast<void *>(PointerLikeTypeTraits<PT2>::getAsVoidPointer(RHS)),
1);
return *this;
}
/// Assignment from elements of the union.
using Base::operator=;
void *getOpaqueValue() const { return Val.getOpaqueValue(); }
void *getOpaqueValue() const { return this->Val.getOpaqueValue(); }
static inline PointerUnion getFromOpaqueValue(void *VP) {
PointerUnion V;
V.Val = ValTy::getFromOpaqueValue(VP);
V.Val = decltype(V.Val)::getFromOpaqueValue(VP);
return V;
}
};
template <typename PT1, typename PT2>
bool operator==(PointerUnion<PT1, PT2> lhs, PointerUnion<PT1, PT2> rhs) {
template <typename ...PTs>
bool operator==(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) {
return lhs.getOpaqueValue() == rhs.getOpaqueValue();
}
template <typename PT1, typename PT2>
bool operator!=(PointerUnion<PT1, PT2> lhs, PointerUnion<PT1, PT2> rhs) {
template <typename ...PTs>
bool operator!=(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) {
return lhs.getOpaqueValue() != rhs.getOpaqueValue();
}
template <typename PT1, typename PT2>
bool operator<(PointerUnion<PT1, PT2> lhs, PointerUnion<PT1, PT2> rhs) {
template <typename ...PTs>
bool operator<(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) {
return lhs.getOpaqueValue() < rhs.getOpaqueValue();
}
// Teach SmallPtrSet that PointerUnion is "basically a pointer", that has
// # low bits available = min(PT1bits,PT2bits)-1.
template <typename PT1, typename PT2>
struct PointerLikeTypeTraits<PointerUnion<PT1, PT2>> {
static inline void *getAsVoidPointer(const PointerUnion<PT1, PT2> &P) {
template <typename ...PTs>
struct PointerLikeTypeTraits<PointerUnion<PTs...>> {
static inline void *getAsVoidPointer(const PointerUnion<PTs...> &P) {
return P.getOpaqueValue();
}
static inline PointerUnion<PT1, PT2> getFromVoidPointer(void *P) {
return PointerUnion<PT1, PT2>::getFromOpaqueValue(P);
static inline PointerUnion<PTs...> getFromVoidPointer(void *P) {
return PointerUnion<PTs...>::getFromOpaqueValue(P);
}
// The number of bits available are the min of the two pointer types.
enum {
NumLowBitsAvailable = PointerLikeTypeTraits<
typename PointerUnion<PT1, PT2>::ValTy>::NumLowBitsAvailable
};
};
/// A pointer union of three pointer types. See documentation for PointerUnion
/// for usage.
template <typename PT1, typename PT2, typename PT3> class PointerUnion3 {
public:
using InnerUnion = PointerUnion<PT1, PT2>;
using ValTy = PointerUnion<InnerUnion, PT3>;
private:
ValTy Val;
struct IsInnerUnion {
ValTy Val;
IsInnerUnion(ValTy val) : Val(val) {}
template <typename T> int is() const {
return Val.template is<InnerUnion>() &&
Val.template get<InnerUnion>().template is<T>();
}
template <typename T> T get() const {
return Val.template get<InnerUnion>().template get<T>();
}
};
struct IsPT3 {
ValTy Val;
IsPT3(ValTy val) : Val(val) {}
template <typename T> int is() const { return Val.template is<T>(); }
template <typename T> T get() const { return Val.template get<T>(); }
};
public:
PointerUnion3() = default;
PointerUnion3(PT1 V) { Val = InnerUnion(V); }
PointerUnion3(PT2 V) { Val = InnerUnion(V); }
PointerUnion3(PT3 V) { Val = V; }
/// Test if the pointer held in the union is null, regardless of
/// which type it is.
bool isNull() const { return Val.isNull(); }
explicit operator bool() const { return !isNull(); }
/// Test if the Union currently holds the type matching T.
template <typename T> int is() const {
// If T is PT1/PT2 choose IsInnerUnion otherwise choose IsPT3.
using Ty = typename ::wpi::PointerUnionTypeSelector<
PT1, T, IsInnerUnion,
::wpi::PointerUnionTypeSelector<PT2, T, IsInnerUnion, IsPT3>>::Return;
return Ty(Val).template is<T>();
}
/// Returns the value of the specified pointer type.
///
/// If the specified pointer type is incorrect, assert.
template <typename T> T get() const {
assert(is<T>() && "Invalid accessor called");
// If T is PT1/PT2 choose IsInnerUnion otherwise choose IsPT3.
using Ty = typename ::wpi::PointerUnionTypeSelector<
PT1, T, IsInnerUnion,
::wpi::PointerUnionTypeSelector<PT2, T, IsInnerUnion, IsPT3>>::Return;
return Ty(Val).template get<T>();
}
/// Returns the current pointer if it is of the specified pointer type,
/// otherwises returns null.
template <typename T> T dyn_cast() const {
if (is<T>())
return get<T>();
return T();
}
/// Assignment from nullptr which just clears the union.
const PointerUnion3 &operator=(std::nullptr_t) {
Val = nullptr;
return *this;
}
/// Assignment operators - Allow assigning into this union from either
/// pointer type, setting the discriminator to remember what it came from.
const PointerUnion3 &operator=(const PT1 &RHS) {
Val = InnerUnion(RHS);
return *this;
}
const PointerUnion3 &operator=(const PT2 &RHS) {
Val = InnerUnion(RHS);
return *this;
}
const PointerUnion3 &operator=(const PT3 &RHS) {
Val = RHS;
return *this;
}
void *getOpaqueValue() const { return Val.getOpaqueValue(); }
static inline PointerUnion3 getFromOpaqueValue(void *VP) {
PointerUnion3 V;
V.Val = ValTy::getFromOpaqueValue(VP);
return V;
}
};
// Teach SmallPtrSet that PointerUnion3 is "basically a pointer", that has
// # low bits available = min(PT1bits,PT2bits,PT2bits)-2.
template <typename PT1, typename PT2, typename PT3>
struct PointerLikeTypeTraits<PointerUnion3<PT1, PT2, PT3>> {
static inline void *getAsVoidPointer(const PointerUnion3<PT1, PT2, PT3> &P) {
return P.getOpaqueValue();
}
static inline PointerUnion3<PT1, PT2, PT3> getFromVoidPointer(void *P) {
return PointerUnion3<PT1, PT2, PT3>::getFromOpaqueValue(P);
}
// The number of bits available are the min of the two pointer types.
enum {
NumLowBitsAvailable = PointerLikeTypeTraits<
typename PointerUnion3<PT1, PT2, PT3>::ValTy>::NumLowBitsAvailable
};
};
template <typename PT1, typename PT2, typename PT3>
bool operator<(PointerUnion3<PT1, PT2, PT3> lhs,
PointerUnion3<PT1, PT2, PT3> rhs) {
return lhs.getOpaqueValue() < rhs.getOpaqueValue();
}
/// A pointer union of four pointer types. See documentation for PointerUnion
/// for usage.
template <typename PT1, typename PT2, typename PT3, typename PT4>
class PointerUnion4 {
public:
using InnerUnion1 = PointerUnion<PT1, PT2>;
using InnerUnion2 = PointerUnion<PT3, PT4>;
using ValTy = PointerUnion<InnerUnion1, InnerUnion2>;
private:
ValTy Val;
public:
PointerUnion4() = default;
PointerUnion4(PT1 V) { Val = InnerUnion1(V); }
PointerUnion4(PT2 V) { Val = InnerUnion1(V); }
PointerUnion4(PT3 V) { Val = InnerUnion2(V); }
PointerUnion4(PT4 V) { Val = InnerUnion2(V); }
/// Test if the pointer held in the union is null, regardless of
/// which type it is.
bool isNull() const { return Val.isNull(); }
explicit operator bool() const { return !isNull(); }
/// Test if the Union currently holds the type matching T.
template <typename T> int is() const {
// If T is PT1/PT2 choose InnerUnion1 otherwise choose InnerUnion2.
using Ty = typename ::wpi::PointerUnionTypeSelector<
PT1, T, InnerUnion1,
::wpi::PointerUnionTypeSelector<PT2, T, InnerUnion1,
InnerUnion2>>::Return;
return Val.template is<Ty>() && Val.template get<Ty>().template is<T>();
}
/// Returns the value of the specified pointer type.
///
/// If the specified pointer type is incorrect, assert.
template <typename T> T get() const {
assert(is<T>() && "Invalid accessor called");
// If T is PT1/PT2 choose InnerUnion1 otherwise choose InnerUnion2.
using Ty = typename ::wpi::PointerUnionTypeSelector<
PT1, T, InnerUnion1,
::wpi::PointerUnionTypeSelector<PT2, T, InnerUnion1,
InnerUnion2>>::Return;
return Val.template get<Ty>().template get<T>();
}
/// Returns the current pointer if it is of the specified pointer type,
/// otherwises returns null.
template <typename T> T dyn_cast() const {
if (is<T>())
return get<T>();
return T();
}
/// Assignment from nullptr which just clears the union.
const PointerUnion4 &operator=(std::nullptr_t) {
Val = nullptr;
return *this;
}
/// Assignment operators - Allow assigning into this union from either
/// pointer type, setting the discriminator to remember what it came from.
const PointerUnion4 &operator=(const PT1 &RHS) {
Val = InnerUnion1(RHS);
return *this;
}
const PointerUnion4 &operator=(const PT2 &RHS) {
Val = InnerUnion1(RHS);
return *this;
}
const PointerUnion4 &operator=(const PT3 &RHS) {
Val = InnerUnion2(RHS);
return *this;
}
const PointerUnion4 &operator=(const PT4 &RHS) {
Val = InnerUnion2(RHS);
return *this;
}
void *getOpaqueValue() const { return Val.getOpaqueValue(); }
static inline PointerUnion4 getFromOpaqueValue(void *VP) {
PointerUnion4 V;
V.Val = ValTy::getFromOpaqueValue(VP);
return V;
}
};
// Teach SmallPtrSet that PointerUnion4 is "basically a pointer", that has
// # low bits available = min(PT1bits,PT2bits,PT2bits)-2.
template <typename PT1, typename PT2, typename PT3, typename PT4>
struct PointerLikeTypeTraits<PointerUnion4<PT1, PT2, PT3, PT4>> {
static inline void *
getAsVoidPointer(const PointerUnion4<PT1, PT2, PT3, PT4> &P) {
return P.getOpaqueValue();
}
static inline PointerUnion4<PT1, PT2, PT3, PT4> getFromVoidPointer(void *P) {
return PointerUnion4<PT1, PT2, PT3, PT4>::getFromOpaqueValue(P);
}
// The number of bits available are the min of the two pointer types.
enum {
NumLowBitsAvailable = PointerLikeTypeTraits<
typename PointerUnion4<PT1, PT2, PT3, PT4>::ValTy>::NumLowBitsAvailable
};
// The number of bits available are the min of the pointer types minus the
// bits needed for the discriminator.
static constexpr int NumLowBitsAvailable = PointerLikeTypeTraits<decltype(
PointerUnion<PTs...>::Val)>::NumLowBitsAvailable;
};
// Teach DenseMap how to use PointerUnions as keys.
template <typename T, typename U> struct DenseMapInfo<PointerUnion<T, U>> {
using Pair = PointerUnion<T, U>;
using FirstInfo = DenseMapInfo<T>;
using SecondInfo = DenseMapInfo<U>;
template <typename ...PTs> struct DenseMapInfo<PointerUnion<PTs...>> {
using Union = PointerUnion<PTs...>;
using FirstInfo =
DenseMapInfo<typename pointer_union_detail::GetFirstType<PTs...>::type>;
static inline Pair getEmptyKey() { return Pair(FirstInfo::getEmptyKey()); }
static inline Union getEmptyKey() { return Union(FirstInfo::getEmptyKey()); }
static inline Pair getTombstoneKey() {
return Pair(FirstInfo::getTombstoneKey());
static inline Union getTombstoneKey() {
return Union(FirstInfo::getTombstoneKey());
}
static unsigned getHashValue(const Pair &PairVal) {
intptr_t key = (intptr_t)PairVal.getOpaqueValue();
static unsigned getHashValue(const Union &UnionVal) {
intptr_t key = (intptr_t)UnionVal.getOpaqueValue();
return DenseMapInfo<intptr_t>::getHashValue(key);
}
static bool isEqual(const Pair &LHS, const Pair &RHS) {
return LHS.template is<T>() == RHS.template is<T>() &&
(LHS.template is<T>() ? FirstInfo::isEqual(LHS.template get<T>(),
RHS.template get<T>())
: SecondInfo::isEqual(LHS.template get<U>(),
RHS.template get<U>()));
static bool isEqual(const Union &LHS, const Union &RHS) {
return LHS == RHS;
}
};

View File

@@ -0,0 +1,82 @@
//===- STLForwardCompat.h - Library features from future STLs ------C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file contains library features backported from future STL versions.
//
// These should be replaced with their STL counterparts as the C++ version LLVM
// is compiled with is updated.
//
//===----------------------------------------------------------------------===//
#ifndef WPIUTIL_WPI_STLFORWARDCOMPAT_H
#define WPIUTIL_WPI_STLFORWARDCOMPAT_H
#include <type_traits>
namespace wpi {
//===----------------------------------------------------------------------===//
// Features from C++17
//===----------------------------------------------------------------------===//
template <typename T>
struct negation // NOLINT(readability-identifier-naming)
: std::integral_constant<bool, !bool(T::value)> {};
template <typename...>
struct conjunction // NOLINT(readability-identifier-naming)
: std::true_type {};
template <typename B1> struct conjunction<B1> : B1 {};
template <typename B1, typename... Bn>
struct conjunction<B1, Bn...>
: std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {};
template <typename...>
struct disjunction // NOLINT(readability-identifier-naming)
: std::false_type {};
template <typename B1> struct disjunction<B1> : B1 {};
template <typename B1, typename... Bn>
struct disjunction<B1, Bn...>
: std::conditional<bool(B1::value), B1, disjunction<Bn...>>::type {};
struct in_place_t // NOLINT(readability-identifier-naming)
{
explicit in_place_t() = default;
};
/// \warning This must not be odr-used, as it cannot be made \c inline in C++14.
constexpr in_place_t in_place; // NOLINT(readability-identifier-naming)
template <typename T>
struct in_place_type_t // NOLINT(readability-identifier-naming)
{
explicit in_place_type_t() = default;
};
template <std::size_t I>
struct in_place_index_t // NOLINT(readability-identifier-naming)
{
explicit in_place_index_t() = default;
};
//===----------------------------------------------------------------------===//
// Features from C++20
//===----------------------------------------------------------------------===//
template <typename T>
struct remove_cvref // NOLINT(readability-identifier-naming)
{
using type = std::remove_cv_t<std::remove_reference_t<T>>;
};
template <typename T>
using remove_cvref_t // NOLINT(readability-identifier-naming)
= typename wpi::remove_cvref<T>::type;
} // namespace wpi
#endif // WPIUTIL_WPI_STLFORWARDCOMPAT_H

View File

@@ -1,9 +1,8 @@
//===- llvm/ADT/SmallPtrSet.h - 'Normally small' pointer set ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -20,7 +19,6 @@
#include "wpi/type_traits.h"
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <initializer_list>
@@ -270,7 +268,7 @@ public:
explicit SmallPtrSetIterator(const void *const *BP, const void *const *E)
: SmallPtrSetIteratorImpl(BP, E) {}
// Most methods provided by baseclass.
// Most methods are provided by the base class.
const PtrTy operator*() const {
assert(Bucket < End);
@@ -327,14 +325,8 @@ class SmallPtrSetImpl : public SmallPtrSetImplBase {
using ConstPtrTraits = PointerLikeTypeTraits<ConstPtrType>;
protected:
// Constructors that forward to the base.
SmallPtrSetImpl(const void **SmallStorage, const SmallPtrSetImpl &that)
: SmallPtrSetImplBase(SmallStorage, that) {}
SmallPtrSetImpl(const void **SmallStorage, unsigned SmallSize,
SmallPtrSetImpl &&that)
: SmallPtrSetImplBase(SmallStorage, SmallSize, std::move(that)) {}
explicit SmallPtrSetImpl(const void **SmallStorage, unsigned SmallSize)
: SmallPtrSetImplBase(SmallStorage, SmallSize) {}
// Forward constructors to the base.
using SmallPtrSetImplBase::SmallPtrSetImplBase;
public:
using iterator = SmallPtrSetIterator<PtrType>;
@@ -353,17 +345,28 @@ public:
return std::make_pair(makeIterator(p.first), p.second);
}
/// Insert the given pointer with an iterator hint that is ignored. This is
/// identical to calling insert(Ptr), but allows SmallPtrSet to be used by
/// std::insert_iterator and std::inserter().
iterator insert(iterator, PtrType Ptr) {
return insert(Ptr).first;
}
/// erase - If the set contains the specified pointer, remove it and return
/// true, otherwise return false.
bool erase(PtrType Ptr) {
return erase_imp(PtrTraits::getAsVoidPointer(Ptr));
}
/// count - Return 1 if the specified pointer is in the set, 0 otherwise.
size_type count(ConstPtrType Ptr) const { return find(Ptr) != end() ? 1 : 0; }
size_type count(ConstPtrType Ptr) const {
return find_imp(ConstPtrTraits::getAsVoidPointer(Ptr)) != EndPointer();
}
iterator find(ConstPtrType Ptr) const {
return makeIterator(find_imp(ConstPtrTraits::getAsVoidPointer(Ptr)));
}
bool contains(ConstPtrType Ptr) const {
return find_imp(ConstPtrTraits::getAsVoidPointer(Ptr)) != EndPointer();
}
template <typename IterT>
void insert(IterT I, IterT E) {
@@ -387,6 +390,32 @@ private:
}
};
/// Equality comparison for SmallPtrSet.
///
/// Iterates over elements of LHS confirming that each value from LHS is also in
/// RHS, and that no additional values are in RHS.
template <typename PtrType>
bool operator==(const SmallPtrSetImpl<PtrType> &LHS,
const SmallPtrSetImpl<PtrType> &RHS) {
if (LHS.size() != RHS.size())
return false;
for (const auto *KV : LHS)
if (!RHS.count(KV))
return false;
return true;
}
/// Inequality comparison for SmallPtrSet.
///
/// Equivalent to !(LHS == RHS).
template <typename PtrType>
bool operator!=(const SmallPtrSetImpl<PtrType> &LHS,
const SmallPtrSetImpl<PtrType> &RHS) {
return !(LHS == RHS);
}
/// SmallPtrSet - This class implements a set which is optimized for holding
/// SmallSize or less elements. This internally rounds up SmallSize to the next
/// power of two if it is not already a power of two. See the comments above
@@ -460,4 +489,4 @@ namespace std {
} // end namespace std
#endif // LLVM_ADT_SMALLPTRSET_H
#endif // WPIUTIL_WPI_SMALLPTRSET_H

View File

@@ -1,9 +1,8 @@
//===- llvm/ADT/SmallSet.h - 'Normally small' sets --------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -16,8 +15,8 @@
#include "wpi/SmallPtrSet.h"
#include "wpi/SmallVector.h"
#include "wpi/Compiler.h"
#include "wpi/iterator.h"
#include "wpi/Compiler.h"
#include "wpi/type_traits.h"
#include <cstddef>
#include <functional>
@@ -233,6 +232,13 @@ public:
return {Set.end()};
}
/// Check if the SmallSet contains the given element.
bool contains(const T &V) const {
if (isSmall())
return vfind(V) != Vector.end();
return Set.find(V) != Set.end();
}
private:
bool isSmall() const { return Set.empty(); }
@@ -249,6 +255,31 @@ private:
template <typename PointeeType, unsigned N>
class SmallSet<PointeeType*, N> : public SmallPtrSet<PointeeType*, N> {};
/// Equality comparison for SmallSet.
///
/// Iterates over elements of LHS confirming that each element is also a member
/// of RHS, and that RHS contains no additional values.
/// Equivalent to N calls to RHS.count.
/// For small-set mode amortized complexity is O(N^2)
/// For large-set mode amortized complexity is linear, worst case is O(N^2) (if
/// every hash collides).
template <typename T, unsigned LN, unsigned RN, typename C>
bool operator==(const SmallSet<T, LN, C> &LHS, const SmallSet<T, RN, C> &RHS) {
if (LHS.size() != RHS.size())
return false;
// All elements in LHS must also be in RHS
return std::all_of(LHS.begin(), LHS.end(), [&RHS](const T &E) { return RHS.count(E); });
}
/// Inequality comparison for SmallSet.
///
/// Equivalent to !(LHS == RHS). See operator== for performance notes.
template <typename T, unsigned LN, unsigned RN, typename C>
bool operator!=(const SmallSet<T, LN, C> &LHS, const SmallSet<T, RN, C> &RHS) {
return !(LHS == RHS);
}
} // end namespace wpi
#endif // LLVM_ADT_SMALLSET_H
#endif // WPIUTIL_WPI_SMALLSET_H

View File

@@ -1,9 +1,8 @@
//===- llvm/ADT/SmallString.h - 'Normally small' strings --------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -29,66 +28,58 @@ public:
SmallString() = default;
/// Initialize from a std::string_view.
SmallString(std::string_view S)
: SmallVector<char, InternalLen>(S.begin(), S.end()) {}
SmallString(std::string_view S) : SmallVector<char, InternalLen>(S.begin(), S.end()) {}
/// Initialize by concatenating a list of std::string_views.
SmallString(std::initializer_list<std::string_view> Refs)
: SmallVector<char, InternalLen>() {
this->append(Refs);
}
/// Initialize with a range.
template<typename ItTy>
SmallString(ItTy S, ItTy E) : SmallVector<char, InternalLen>(S, E) {}
// Note that in order to add new overloads for append & assign, we have to
// duplicate the inherited versions so as not to inadvertently hide them.
/// @}
/// @name String Assignment
/// @{
/// Assign from a repeated element.
void assign(size_t NumElts, char Elt) {
this->SmallVectorImpl<char>::assign(NumElts, Elt);
}
/// Assign from an iterator pair.
template<typename in_iter>
void assign(in_iter S, in_iter E) {
this->clear();
SmallVectorImpl<char>::append(S, E);
}
using SmallVector<char, InternalLen>::assign;
/// Assign from a std::string_view.
void assign(std::string_view RHS) {
this->clear();
SmallVectorImpl<char>::append(RHS.begin(), RHS.end());
SmallVectorImpl<char>::assign(RHS.begin(), RHS.end());
}
/// Assign from a SmallVector.
void assign(const SmallVectorImpl<char> &RHS) {
/// Assign from a list of std::string_views.
void assign(std::initializer_list<std::string_view> Refs) {
this->clear();
SmallVectorImpl<char>::append(RHS.begin(), RHS.end());
append(Refs);
}
/// @}
/// @name String Concatenation
/// @{
/// Append from an iterator pair.
template<typename in_iter>
void append(in_iter S, in_iter E) {
SmallVectorImpl<char>::append(S, E);
}
void append(size_t NumInputs, char Elt) {
SmallVectorImpl<char>::append(NumInputs, Elt);
}
using SmallVector<char, InternalLen>::append;
/// Append from a std::string_view.
void append(std::string_view RHS) {
SmallVectorImpl<char>::append(RHS.begin(), RHS.end());
}
/// Append from a SmallVector.
void append(const SmallVectorImpl<char> &RHS) {
SmallVectorImpl<char>::append(RHS.begin(), RHS.end());
/// Append from a list of std::string_views.
void append(std::initializer_list<std::string_view> Refs) {
size_t SizeNeeded = this->size();
for (std::string_view Ref : Refs)
SizeNeeded += Ref.size();
this->reserve(SizeNeeded);
auto CurEnd = this->end();
for (std::string_view Ref : Refs) {
this->uninitialized_copy(Ref.begin(), Ref.end(), CurEnd);
CurEnd += Ref.size();
}
this->set_size(SizeNeeded);
}
/// @}
@@ -185,10 +176,7 @@ public:
// Extra methods.
/// Explicit conversion to std::string_view.
std::string_view str() const { return {this->begin(), this->size()}; }
/// Explicit conversion to std::string.
std::string string() const { return {this->begin(), this->size()}; }
std::string_view str() const { return std::string_view(this->begin(), this->size()); }
// TODO: Make this const, if it's safe...
const char* c_str() {
@@ -200,13 +188,16 @@ public:
/// Implicit conversion to std::string_view.
operator std::string_view() const { return str(); }
/// Explicit conversion to std::string.
std::string string() const { return {this->begin(), this->size()}; }
/// Implicit conversion to std::string.
operator std::string() const { return string(); }
// Extra operators.
const SmallString &operator=(std::string_view RHS) {
this->clear();
return *this += RHS;
SmallString &operator=(std::string_view RHS) {
this->assign(RHS);
return *this;
}
SmallString &operator+=(std::string_view RHS) {
@@ -221,4 +212,4 @@ public:
} // end namespace wpi
#endif // LLVM_ADT_SMALLSTRING_H
#endif // WPIUTIL_WPI_SMALLSTRING_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,8 @@
//===- StringMap.h - String Hash table map interface ------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -14,38 +13,20 @@
#ifndef WPIUTIL_WPI_STRINGMAP_H
#define WPIUTIL_WPI_STRINGMAP_H
#include "wpi/StringMapEntry.h"
#include "wpi/MemAlloc.h"
#include "wpi/SmallVector.h"
#include "wpi/iterator.h"
#include "wpi/iterator_range.h"
#include "wpi/MemAlloc.h"
#include "wpi/PointerLikeTypeTraits.h"
#include "wpi/ErrorHandling.h"
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <initializer_list>
#include <iterator>
#include <string_view>
#include <utility>
namespace wpi {
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 {
size_t StrLen;
public:
explicit StringMapEntryBase(size_t Len) : StrLen(Len) {}
size_t getKeyLength() const { return StrLen; }
};
template <typename ValueTy> class StringMapConstIterator;
template <typename ValueTy> class StringMapIterator;
template <typename ValueTy> class StringMapKeyIterator;
/// StringMapImpl - This is the base class of StringMap that is shared among
/// all of its instantiations.
@@ -61,8 +42,7 @@ protected:
unsigned ItemSize;
protected:
explicit StringMapImpl(unsigned itemSize)
: ItemSize(itemSize) {}
explicit StringMapImpl(unsigned itemSize) : ItemSize(itemSize) {}
StringMapImpl(StringMapImpl &&RHS) noexcept
: TheTable(RHS.TheTable), NumBuckets(RHS.NumBuckets),
NumItems(RHS.NumItems), NumTombstones(RHS.NumTombstones),
@@ -101,10 +81,12 @@ protected:
void init(unsigned Size);
public:
static constexpr uintptr_t TombstoneIntVal =
static_cast<uintptr_t>(-1)
<< PointerLikeTypeTraits<StringMapEntryBase *>::NumLowBitsAvailable;
static StringMapEntryBase *getTombstoneVal() {
uintptr_t Val = static_cast<uintptr_t>(-1);
Val <<= PointerLikeTypeTraits<StringMapEntryBase *>::NumLowBitsAvailable;
return reinterpret_cast<StringMapEntryBase *>(Val);
return reinterpret_cast<StringMapEntryBase *>(TombstoneIntVal);
}
unsigned getNumBuckets() const { return NumBuckets; }
@@ -121,82 +103,6 @@ public:
}
};
/// StringMapEntry - This is used to represent one value that is inserted into
/// a StringMap. It contains the Value itself and the key: the string length
/// and data.
template<typename ValueTy>
class StringMapEntry : public StringMapEntryBase {
public:
ValueTy second;
explicit StringMapEntry(size_t strLen)
: StringMapEntryBase(strLen), second() {}
template <typename... InitTy>
StringMapEntry(size_t strLen, InitTy &&... InitVals)
: StringMapEntryBase(strLen), second(std::forward<InitTy>(InitVals)...) {}
StringMapEntry(StringMapEntry &E) = delete;
std::string_view getKey() const {
return {getKeyData(), getKeyLength()};
}
const ValueTy &getValue() const { return second; }
ValueTy &getValue() { return second; }
void setValue(const ValueTy &V) { second = V; }
/// getKeyData - Return the start of the string data that is the key for this
/// value. The string data is always stored immediately after the
/// StringMapEntry object.
const char *getKeyData() const {return reinterpret_cast<const char*>(this+1);}
std::string_view first() const { return {getKeyData(), getKeyLength()}; }
/// Create a StringMapEntry for the specified key construct the value using
/// \p InitiVals.
template <typename... InitTy>
static StringMapEntry *Create(std::string_view Key, InitTy &&... InitVals) {
size_t KeyLength = Key.size();
// Allocate a new item with space for the string at the end and a null
// terminator.
size_t AllocSize = sizeof(StringMapEntry) + KeyLength + 1;
StringMapEntry *NewItem =
static_cast<StringMapEntry*>(safe_malloc(AllocSize));
// Construct the value.
new (NewItem) StringMapEntry(KeyLength, std::forward<InitTy>(InitVals)...);
// Copy the string information.
char *StrBuffer = const_cast<char*>(NewItem->getKeyData());
if (KeyLength > 0)
memcpy(StrBuffer, Key.data(), KeyLength);
StrBuffer[KeyLength] = 0; // Null terminate for convenience of clients.
return NewItem;
}
static StringMapEntry *Create(std::string_view Key) {
return Create(Key, ValueTy());
}
/// GetStringMapEntryFromKeyData - Given key data that is known to be embedded
/// into a StringMapEntry, return the StringMapEntry itself.
static StringMapEntry &GetStringMapEntryFromKeyData(const char *KeyData) {
char *Ptr = const_cast<char*>(KeyData) - sizeof(StringMapEntry<ValueTy>);
return *reinterpret_cast<StringMapEntry*>(Ptr);
}
/// Destroy - Destroy this StringMapEntry, releasing memory back to the
/// specified allocator.
void Destroy() {
// Free memory referenced by the item.
this->~StringMapEntry();
std::free(static_cast<void *>(this));
}
};
/// StringMap - This is an unconventional map that is specialized for handling
/// keys that are "strings", which are basically ranges of bytes. This does some
/// funky memory allocation and hashing things to make it extremely efficient,
@@ -209,7 +115,7 @@ public:
StringMap() : StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))) {}
explicit StringMap(unsigned InitialSize)
: StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))) {}
: StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))) {}
StringMap(std::initializer_list<std::pair<std::string_view, ValueTy>> List)
: StringMapImpl(List.size(), static_cast<unsigned>(sizeof(MapEntryTy))) {
@@ -268,14 +174,14 @@ public:
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
StringMapEntryBase *Bucket = TheTable[I];
if (Bucket && Bucket != getTombstoneVal()) {
static_cast<MapEntryTy*>(Bucket)->Destroy();
static_cast<MapEntryTy *>(Bucket)->Destroy();
}
}
}
free(TheTable);
}
using key_type = const char*;
using key_type = const char *;
using mapped_type = ValueTy;
using value_type = StringMapEntry<ValueTy>;
using size_type = size_t;
@@ -283,17 +189,13 @@ public:
using const_iterator = StringMapConstIterator<ValueTy>;
using iterator = StringMapIterator<ValueTy>;
iterator begin() {
return iterator(TheTable, NumBuckets == 0);
}
iterator end() {
return iterator(TheTable+NumBuckets, true);
}
iterator begin() { return iterator(TheTable, NumBuckets == 0); }
iterator end() { return iterator(TheTable + NumBuckets, true); }
const_iterator begin() const {
return const_iterator(TheTable, NumBuckets == 0);
}
const_iterator end() const {
return const_iterator(TheTable+NumBuckets, true);
return const_iterator(TheTable + NumBuckets, true);
}
iterator_range<StringMapKeyIterator<ValueTy>> keys() const {
@@ -303,14 +205,16 @@ public:
iterator find(std::string_view Key) {
int Bucket = FindKey(Key);
if (Bucket == -1) return end();
return iterator(TheTable+Bucket, true);
if (Bucket == -1)
return end();
return iterator(TheTable + Bucket, true);
}
const_iterator find(std::string_view Key) const {
int Bucket = FindKey(Key);
if (Bucket == -1) return end();
return const_iterator(TheTable+Bucket, true);
if (Bucket == -1)
return end();
return const_iterator(TheTable + Bucket, true);
}
/// lookup - Return the entry for the specified key, or a default
@@ -327,10 +231,33 @@ public:
ValueTy &operator[](std::string_view Key) { return try_emplace(Key).first->second; }
/// count - Return 1 if the element is in the map, 0 otherwise.
size_type count(std::string_view Key) const {
return find(Key) == end() ? 0 : 1;
size_type count(std::string_view Key) const { return find(Key) == end() ? 0 : 1; }
template <typename InputTy>
size_type count(const StringMapEntry<InputTy> &MapEntry) const {
return count(MapEntry.getKey());
}
/// equal - check whether both of the containers are equal.
bool operator==(const StringMap &RHS) const {
if (size() != RHS.size())
return false;
for (const auto &KeyValue : *this) {
auto FindInRHS = RHS.find(KeyValue.getKey());
if (FindInRHS == RHS.end())
return false;
if (!(KeyValue.getValue() == FindInRHS->getValue()))
return false;
}
return true;
}
bool operator!=(const StringMap &RHS) const { return !(*this == RHS); }
/// insert - Insert the specified key/value pair into the map. If the key
/// already exists in the map, return false and ignore the request, otherwise
/// insert it and return true.
@@ -338,7 +265,7 @@ public:
unsigned BucketNo = LookupBucketFor(KeyValue->getKey());
StringMapEntryBase *&Bucket = TheTable[BucketNo];
if (Bucket && Bucket != getTombstoneVal())
return false; // Already exists in map.
return false; // Already exists in map.
if (Bucket == getTombstoneVal())
--NumTombstones;
@@ -358,6 +285,16 @@ public:
return try_emplace(KV.first, std::move(KV.second));
}
/// Inserts an element or assigns to the current element if the key already
/// exists. The return type is the same as try_emplace.
template <typename V>
std::pair<iterator, bool> insert_or_assign(std::string_view Key, V &&Val) {
auto Ret = try_emplace(Key, std::forward<V>(Val));
if (!Ret.second)
Ret.first->second = std::forward<V>(Val);
return Ret;
}
/// Emplace a new element for the specified key into the map if the key isn't
/// already in the map. The bool component of the returned pair is true
/// if and only if the insertion takes place, and the iterator component of
@@ -382,14 +319,15 @@ public:
// clear - Empties out the StringMap
void clear() {
if (empty()) return;
if (empty())
return;
// Zap all values, resetting the keys back to non-present (not tombstone),
// which is safe because we're removing all elements.
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
StringMapEntryBase *&Bucket = TheTable[I];
if (Bucket && Bucket != getTombstoneVal()) {
static_cast<MapEntryTy*>(Bucket)->Destroy();
static_cast<MapEntryTy *>(Bucket)->Destroy();
}
Bucket = nullptr;
}
@@ -400,9 +338,7 @@ public:
/// remove - Remove the specified key/value pair from the map, but do not
/// erase it. This aborts if the key is not in the map.
void remove(MapEntryTy *KeyValue) {
RemoveKey(KeyValue);
}
void remove(MapEntryTy *KeyValue) { RemoveKey(KeyValue); }
void erase(iterator I) {
MapEntryTy &V = *I;
@@ -412,7 +348,8 @@ public:
bool erase(std::string_view Key) {
iterator I = find(Key);
if (I == end()) return false;
if (I == end())
return false;
erase(I);
return true;
}
@@ -431,7 +368,8 @@ public:
explicit StringMapIterBase(StringMapEntryBase **Bucket,
bool NoAdvance = false)
: Ptr(Bucket) {
if (!NoAdvance) AdvancePastEmptyBuckets();
if (!NoAdvance)
AdvancePastEmptyBuckets();
}
DerivedTy &operator=(const DerivedTy &Other) {
@@ -439,13 +377,9 @@ public:
return static_cast<DerivedTy &>(*this);
}
#if __cplusplus < 202002L
bool operator==(const DerivedTy &RHS) const { return Ptr == RHS.Ptr; }
#else
friend bool operator==(const DerivedTy &LHS, const DerivedTy &RHS) {
return LHS.Ptr == RHS.Ptr;
}
#endif
DerivedTy &operator++() { // Preincrement
++Ptr;
@@ -490,15 +424,13 @@ class StringMapConstIterator
const StringMapEntry<ValueTy>>;
public:
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);
const StringMapEntry<ValueTy> &operator*() const {
return *static_cast<const StringMapEntry<ValueTy> *>(*this->Ptr);
}
};
@@ -509,15 +441,13 @@ class StringMapIterator : public StringMapIterBase<StringMapIterator<ValueTy>,
StringMapIterBase<StringMapIterator<ValueTy>, StringMapEntry<ValueTy>>;
public:
using value_type = StringMapEntry<ValueTy>;
StringMapIterator() = default;
explicit StringMapIterator(StringMapEntryBase **Bucket,
bool NoAdvance = false)
: 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 {
@@ -635,4 +565,4 @@ inline bool operator>=(const StringMap<ValueTy>& lhs,
} // end namespace wpi
#endif // LLVM_ADT_STRINGMAP_H
#endif // WPIUTIL_WPI_STRINGMAP_H

View File

@@ -0,0 +1,143 @@
//===- StringMapEntry.h - String Hash table map interface -------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines the StringMapEntry class - it is intended to be a low
// dependency implementation detail of StringMap that is more suitable for
// inclusion in public headers than StringMap.h itself is.
//
//===----------------------------------------------------------------------===//
#ifndef WPIUTIL_WPI_STRINGMAPENTRY_H
#define WPIUTIL_WPI_STRINGMAPENTRY_H
#include "wpi/MemAlloc.h"
#include <cassert>
#include <cstring>
#include <optional>
#include <string_view>
namespace wpi {
/// StringMapEntryBase - Shared base class of StringMapEntry instances.
class StringMapEntryBase {
size_t keyLength;
public:
explicit StringMapEntryBase(size_t keyLength) : keyLength(keyLength) {}
size_t getKeyLength() const { return keyLength; }
protected:
/// Helper to tail-allocate \p Key. It'd be nice to generalize this so it
/// could be reused elsewhere, maybe even taking an wpi::function_ref to
/// type-erase the allocator and put it in a source file.
static void *allocateWithKey(size_t EntrySize, size_t EntryAlign,
std::string_view Key) {
size_t KeyLength = Key.size();
// Allocate a new item with space for the string at the end and a null
// terminator.
size_t AllocSize = EntrySize + KeyLength + 1;
void *Allocation = safe_malloc(AllocSize);
assert(Allocation && "Unhandled out-of-memory");
// Copy the string information.
char *Buffer = reinterpret_cast<char *>(Allocation) + EntrySize;
if (KeyLength > 0)
::memcpy(Buffer, Key.data(), KeyLength);
Buffer[KeyLength] = 0; // Null terminate for convenience of clients.
return Allocation;
}
};
/// StringMapEntryStorage - Holds the value in a StringMapEntry.
///
/// Factored out into a separate base class to make it easier to specialize.
/// This is primarily intended to support StringSet, which doesn't need a value
/// stored at all.
template <typename ValueTy>
class StringMapEntryStorage : public StringMapEntryBase {
public:
ValueTy second;
explicit StringMapEntryStorage(size_t keyLength)
: StringMapEntryBase(keyLength), second() {}
template <typename... InitTy>
StringMapEntryStorage(size_t keyLength, InitTy &&... initVals)
: StringMapEntryBase(keyLength),
second(std::forward<InitTy>(initVals)...) {}
StringMapEntryStorage(StringMapEntryStorage &e) = delete;
const ValueTy &getValue() const { return second; }
ValueTy &getValue() { return second; }
void setValue(const ValueTy &V) { second = V; }
};
template <> class StringMapEntryStorage<std::nullopt_t> : public StringMapEntryBase {
public:
explicit StringMapEntryStorage(size_t keyLength, std::nullopt_t = std::nullopt)
: StringMapEntryBase(keyLength) {}
StringMapEntryStorage(StringMapEntryStorage &entry) = delete;
std::nullopt_t getValue() const { return std::nullopt; }
};
/// StringMapEntry - This is used to represent one value that is inserted into
/// a StringMap. It contains the Value itself and the key: the string length
/// and data.
template <typename ValueTy>
class StringMapEntry final : public StringMapEntryStorage<ValueTy> {
public:
using StringMapEntryStorage<ValueTy>::StringMapEntryStorage;
std::string_view getKey() const {
return std::string_view(getKeyData(), this->getKeyLength());
}
/// getKeyData - Return the start of the string data that is the key for this
/// value. The string data is always stored immediately after the
/// StringMapEntry object.
const char *getKeyData() const {
return reinterpret_cast<const char *>(this + 1);
}
std::string_view first() const {
return std::string_view(getKeyData(), this->getKeyLength());
}
/// Create a StringMapEntry for the specified key construct the value using
/// \p InitiVals.
template <typename... InitTy>
static StringMapEntry *Create(std::string_view key,
InitTy &&... initVals) {
return new (StringMapEntryBase::allocateWithKey(
sizeof(StringMapEntry), alignof(StringMapEntry), key))
StringMapEntry(key.size(), std::forward<InitTy>(initVals)...);
}
/// GetStringMapEntryFromKeyData - Given key data that is known to be embedded
/// into a StringMapEntry, return the StringMapEntry itself.
static StringMapEntry &GetStringMapEntryFromKeyData(const char *keyData) {
char *ptr = const_cast<char *>(keyData) - sizeof(StringMapEntry<ValueTy>);
return *reinterpret_cast<StringMapEntry *>(ptr);
}
/// Destroy - Destroy this StringMapEntry, releasing memory back to the
/// specified allocator.
void Destroy() {
// Free memory referenced by the item.
this->~StringMapEntry();
std::free(static_cast<void *>(this));
}
};
} // end namespace wpi
#endif // WPIUTIL_WPI_STRINGMAPENTRY_H

View File

@@ -1,9 +1,8 @@
//===- SwapByteOrder.h - Generic and optimized byte swaps -------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -15,19 +14,43 @@
#ifndef WPIUTIL_WPI_SWAPBYTEORDER_H
#define WPIUTIL_WPI_SWAPBYTEORDER_H
#include "wpi/Compiler.h"
#include <cstddef>
#include <stdint.h>
#include <cstdint>
#include <type_traits>
#if defined(_MSC_VER) && !defined(_DEBUG)
#include <stdlib.h>
#endif
namespace wpi {
namespace sys {
#if defined(__linux__) || defined(__GNU__) || defined(__HAIKU__) || \
defined(__Fuchsia__) || defined(__EMSCRIPTEN__)
#include <endian.h>
#elif defined(_AIX)
#include <sys/machine.h>
#elif defined(__sun)
/* Solaris provides _BIG_ENDIAN/_LITTLE_ENDIAN selector in sys/types.h */
#include <sys/types.h>
#define BIG_ENDIAN 4321
#define LITTLE_ENDIAN 1234
#if defined(_BIG_ENDIAN)
#define BYTE_ORDER BIG_ENDIAN
#else
#define BYTE_ORDER LITTLE_ENDIAN
#endif
#elif defined(__MVS__)
#define BIG_ENDIAN 4321
#define LITTLE_ENDIAN 1234
#define BYTE_ORDER BIG_ENDIAN
#else
#if !defined(BYTE_ORDER) && !defined(_WIN32)
#include <machine/endian.h>
#endif
#endif
/// SwapByteOrder_16 - This function returns a byte-swapped representation of
namespace wpi {
/// ByteSwap_16 - This function returns a byte-swapped representation of
/// the 16-bit argument.
inline uint16_t SwapByteOrder_16(uint16_t value) {
inline uint16_t ByteSwap_16(uint16_t value) {
#if defined(_MSC_VER) && !defined(_DEBUG)
// The DLL version of the runtime lacks these functions (bug!?), but in a
// release build they're replaced with BSWAP instructions anyway.
@@ -39,10 +62,9 @@ inline uint16_t SwapByteOrder_16(uint16_t value) {
#endif
}
/// SwapByteOrder_32 - This function returns a byte-swapped representation of
/// the 32-bit argument.
inline uint32_t SwapByteOrder_32(uint32_t value) {
#if defined(__llvm__) || (LLVM_GNUC_PREREQ(4, 3, 0) && !defined(__ICC))
/// This function returns a byte-swapped representation of the 32-bit argument.
inline uint32_t ByteSwap_32(uint32_t value) {
#if defined(__llvm__) || (defined(__GNUC__) && !defined(__ICC))
return __builtin_bswap32(value);
#elif defined(_MSC_VER) && !defined(_DEBUG)
return _byteswap_ulong(value);
@@ -55,45 +77,55 @@ inline uint32_t SwapByteOrder_32(uint32_t value) {
#endif
}
/// SwapByteOrder_64 - This function returns a byte-swapped representation of
/// the 64-bit argument.
inline uint64_t SwapByteOrder_64(uint64_t value) {
#if defined(__llvm__) || (LLVM_GNUC_PREREQ(4, 3, 0) && !defined(__ICC))
/// This function returns a byte-swapped representation of the 64-bit argument.
inline uint64_t ByteSwap_64(uint64_t value) {
#if defined(__llvm__) || (defined(__GNUC__) && !defined(__ICC))
return __builtin_bswap64(value);
#elif defined(_MSC_VER) && !defined(_DEBUG)
return _byteswap_uint64(value);
#else
uint64_t Hi = SwapByteOrder_32(uint32_t(value));
uint32_t Lo = SwapByteOrder_32(uint32_t(value >> 32));
uint64_t Hi = ByteSwap_32(uint32_t(value));
uint32_t Lo = ByteSwap_32(uint32_t(value >> 32));
return (Hi << 32) | Lo;
#endif
}
namespace sys {
#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN
constexpr bool IsBigEndianHost = true;
#else
constexpr bool IsBigEndianHost = false;
#endif
static const bool IsLittleEndianHost = !IsBigEndianHost;
inline unsigned char getSwappedBytes(unsigned char C) { return C; }
inline signed char getSwappedBytes(signed char C) { return C; }
inline char getSwappedBytes(char C) { return C; }
inline unsigned short getSwappedBytes(unsigned short C) { return SwapByteOrder_16(C); }
inline signed short getSwappedBytes( signed short C) { return SwapByteOrder_16(C); }
inline unsigned short getSwappedBytes(unsigned short C) { return ByteSwap_16(C); }
inline signed short getSwappedBytes( signed short C) { return ByteSwap_16(C); }
inline unsigned int getSwappedBytes(unsigned int C) { return SwapByteOrder_32(C); }
inline signed int getSwappedBytes( signed int C) { return SwapByteOrder_32(C); }
inline unsigned int getSwappedBytes(unsigned int C) { return ByteSwap_32(C); }
inline signed int getSwappedBytes( signed int C) { return ByteSwap_32(C); }
#if __LONG_MAX__ == __INT_MAX__
inline unsigned long getSwappedBytes(unsigned long C) { return SwapByteOrder_32(C); }
inline signed long getSwappedBytes( signed long C) { return SwapByteOrder_32(C); }
#elif __LONG_MAX__ == __LONG_LONG_MAX__
inline unsigned long getSwappedBytes(unsigned long C) { return SwapByteOrder_64(C); }
inline signed long getSwappedBytes( signed long C) { return SwapByteOrder_64(C); }
#else
#error "Unknown long size!"
#endif
inline unsigned long getSwappedBytes(unsigned long C) {
// Handle LLP64 and LP64 platforms.
return sizeof(long) == sizeof(int) ? ByteSwap_32((uint32_t)C)
: ByteSwap_64((uint64_t)C);
}
inline signed long getSwappedBytes(signed long C) {
// Handle LLP64 and LP64 platforms.
return sizeof(long) == sizeof(int) ? ByteSwap_32((uint32_t)C)
: ByteSwap_64((uint64_t)C);
}
inline unsigned long long getSwappedBytes(unsigned long long C) {
return SwapByteOrder_64(C);
return ByteSwap_64(C);
}
inline signed long long getSwappedBytes(signed long long C) {
return SwapByteOrder_64(C);
return ByteSwap_64(C);
}
inline float getSwappedBytes(float C) {
@@ -102,7 +134,7 @@ inline float getSwappedBytes(float C) {
float f;
} in, out;
in.f = C;
out.i = SwapByteOrder_32(in.i);
out.i = ByteSwap_32(in.i);
return out.f;
}
@@ -112,10 +144,16 @@ inline double getSwappedBytes(double C) {
double d;
} in, out;
in.d = C;
out.i = SwapByteOrder_64(in.i);
out.i = ByteSwap_64(in.i);
return out.d;
}
template <typename T>
inline std::enable_if_t<std::is_enum<T>::value, T> getSwappedBytes(T C) {
return static_cast<T>(
getSwappedBytes(static_cast<std::underlying_type_t<T>>(C)));
}
template<typename T>
inline void swapByteOrder(T &Value) {
Value = getSwappedBytes(Value);

View File

@@ -1,9 +1,8 @@
//===- VersionTuple.h - Version Number Handling -----------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
@@ -15,10 +14,14 @@
#ifndef WPIUTIL_WPI_VERSIONTUPLE_H
#define WPIUTIL_WPI_VERSIONTUPLE_H
#include "wpi/DenseMapInfo.h"
#include "wpi/Hashing.h"
#include <optional>
#include <string>
#include <tuple>
namespace wpi {
class raw_ostream;
/// Represents a version number in the form major[.minor[.subminor[.build]]].
class VersionTuple {
@@ -85,6 +88,27 @@ public:
return Build;
}
/// Return a version tuple that contains only the first 3 version components.
VersionTuple withoutBuild() const {
if (HasBuild)
return VersionTuple(Major, Minor, Subminor);
return *this;
}
/// Return a version tuple that contains only components that are non-zero.
VersionTuple normalize() const {
VersionTuple Result = *this;
if (Result.Build == 0) {
Result.HasBuild = false;
if (Result.Subminor == 0) {
Result.HasSubminor = false;
if (Result.Minor == 0)
Result.HasMinor = false;
}
}
return Result;
}
/// Determine if two version numbers are equivalent. If not
/// provided, minor and subminor version numbers are considered to be zero.
friend bool operator==(const VersionTuple &X, const VersionTuple &Y) {

View File

@@ -1,9 +1,8 @@
//===-- WindowsError.h - Support for mapping windows errors to posix-------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

View File

@@ -1,9 +1,8 @@
//===- 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.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -11,7 +10,6 @@
#define WPIUTIL_WPI_ITERATOR_H
#include "wpi/iterator_range.h"
#include <algorithm>
#include <cstddef>
#include <iterator>
#include <type_traits>
@@ -65,9 +63,14 @@ namespace wpi {
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> {
class iterator_facade_base {
public:
using iterator_category = IteratorCategoryT;
using value_type = T;
using difference_type = DifferenceTypeT;
using pointer = PointerT;
using reference = ReferenceT;
protected:
enum {
IsRandomAccess = std::is_base_of<std::random_access_iterator_tag,
@@ -143,28 +146,30 @@ public:
return tmp;
}
#ifndef __cpp_impl_three_way_comparison
bool operator!=(const DerivedT &RHS) const {
return !static_cast<const DerivedT *>(this)->operator==(RHS);
return !(static_cast<const DerivedT &>(*this) == RHS);
}
#endif
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);
return !(static_cast<const DerivedT &>(*this) < RHS) &&
!(static_cast<const DerivedT &>(*this) == 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);
return !(static_cast<const DerivedT &>(*this) > 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);
return !(static_cast<const DerivedT &>(*this) < RHS);
}
PointerT operator->() { return &static_cast<DerivedT *>(this)->operator*(); }
@@ -195,14 +200,14 @@ template <
typename T = typename std::iterator_traits<WrappedIteratorT>::value_type,
typename DifferenceTypeT =
typename std::iterator_traits<WrappedIteratorT>::difference_type,
typename PointerT = typename std::conditional<
typename PointerT = std::conditional_t<
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<
typename std::iterator_traits<WrappedIteratorT>::pointer, T *>,
typename ReferenceT = std::conditional_t<
std::is_same<T, typename std::iterator_traits<
WrappedIteratorT>::value_type>::value,
typename std::iterator_traits<WrappedIteratorT>::reference, T &>::type>
typename std::iterator_traits<WrappedIteratorT>::reference, T &>>
class iterator_adaptor_base
: public iterator_facade_base<DerivedT, IteratorCategoryT, T,
DifferenceTypeT, PointerT, ReferenceT> {
@@ -261,12 +266,16 @@ public:
return *static_cast<DerivedT *>(this);
}
bool operator==(const DerivedT &RHS) const { return I == RHS.I; }
bool operator<(const DerivedT &RHS) const {
friend bool operator==(const iterator_adaptor_base &LHS,
const iterator_adaptor_base &RHS) {
return LHS.I == RHS.I;
}
friend bool operator<(const iterator_adaptor_base &LHS,
const iterator_adaptor_base &RHS) {
static_assert(
BaseT::IsRandomAccess,
"Relational operators are only defined for random access iterators.");
return I < RHS.I;
return LHS.I < RHS.I;
}
ReferenceT operator*() const { return *I; }
@@ -282,8 +291,8 @@ public:
/// using iterator = pointee_iterator<SmallVectorImpl<T *>::iterator>;
/// \endcode
template <typename WrappedIteratorT,
typename T = typename std::remove_reference<
decltype(**std::declval<WrappedIteratorT>())>::type>
typename T = std::remove_reference_t<decltype(
**std::declval<WrappedIteratorT>())>>
struct pointee_iterator
: iterator_adaptor_base<
pointee_iterator<WrappedIteratorT, T>, WrappedIteratorT,
@@ -334,6 +343,13 @@ make_pointer_range(RangeT &&Range) {
PointerIteratorT(std::end(std::forward<RangeT>(Range))));
}
template <typename WrappedIteratorT,
typename T1 = std::remove_reference_t<decltype(
**std::declval<WrappedIteratorT>())>,
typename T2 = std::add_pointer_t<T1>>
using raw_pointer_iterator =
pointer_iterator<pointee_iterator<WrappedIteratorT, T1>, T2>;
} // end namespace wpi
#endif // LLVM_ADT_ITERATOR_H
#endif // WPIUTIL_WPI_ITERATOR_H

View File

@@ -1,9 +1,8 @@
//===- iterator_range.h - A range adaptor for iterators ---------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
@@ -19,7 +18,6 @@
#ifndef WPIUTIL_WPI_ITERATOR_RANGE_H
#define WPIUTIL_WPI_ITERATOR_RANGE_H
#include <iterator>
#include <utility>
namespace wpi {
@@ -45,6 +43,7 @@ public:
IteratorT begin() const { return begin_iterator; }
IteratorT end() const { return end_iterator; }
bool empty() const { return begin_iterator == end_iterator; }
};
/// Convenience function for iterating over sub-ranges.
@@ -59,11 +58,6 @@ template <typename T> iterator_range<T> make_range(std::pair<T, T> p) {
return iterator_range<T>(std::move(p.first), std::move(p.second));
}
template <typename T>
iterator_range<decltype(adl_begin(std::declval<T>()))> drop_begin(T &&t,
int n) {
return make_range(std::next(adl_begin(t), n), adl_end(t));
}
}
#endif

View File

@@ -1,9 +1,8 @@
//===- raw_os_ostream.h - std::ostream adaptor for raw_ostream --*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//

View File

@@ -1,9 +1,8 @@
//===--- raw_ostream.h - Raw output stream ----------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -17,18 +16,24 @@
#include "wpi/SmallVector.h"
#include "wpi/span.h"
#include <cassert>
#include <chrono>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <string>
#if __cplusplus > 201402L
#include <string_view>
#include <vector>
#endif
#include <system_error>
#include <type_traits>
#include <vector>
namespace fs {
enum FileAccess : unsigned;
enum OpenFlags : unsigned;
enum CreationDisposition : unsigned;
class FileLocker;
} // end namespace fs
namespace wpi {
@@ -38,7 +43,16 @@ namespace wpi {
/// buffered disciplines etc. It is a simple buffer that outputs
/// a chunk at a time.
class raw_ostream {
public:
// Class kinds to support LLVM-style RTTI.
enum class OStreamKind {
OK_OStream,
OK_FDStream,
};
private:
OStreamKind Kind;
/// 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
@@ -59,7 +73,11 @@ private:
/// this buffer.
char *OutBufStart, *OutBufEnd, *OutBufCur;
enum BufferKind {
/// Optional stream this stream is tied to. If this stream is written to, the
/// tied-to stream will be flushed first.
raw_ostream *TiedStream = nullptr;
enum class BufferKind {
Unbuffered = 0,
InternalBuffer,
ExternalBuffer
@@ -67,7 +85,7 @@ private:
public:
// color order matches ANSI escape sequence, don't change
enum Colors {
enum class Colors {
BLACK = 0,
RED,
GREEN,
@@ -76,11 +94,25 @@ public:
MAGENTA,
CYAN,
WHITE,
SAVEDCOLOR
SAVEDCOLOR,
RESET,
};
explicit raw_ostream(bool unbuffered = false)
: BufferMode(unbuffered ? Unbuffered : InternalBuffer) {
static constexpr Colors BLACK = Colors::BLACK;
static constexpr Colors RED = Colors::RED;
static constexpr Colors GREEN = Colors::GREEN;
static constexpr Colors YELLOW = Colors::YELLOW;
static constexpr Colors BLUE = Colors::BLUE;
static constexpr Colors MAGENTA = Colors::MAGENTA;
static constexpr Colors CYAN = Colors::CYAN;
static constexpr Colors WHITE = Colors::WHITE;
static constexpr Colors SAVEDCOLOR = Colors::SAVEDCOLOR;
static constexpr Colors RESET = Colors::RESET;
explicit raw_ostream(bool unbuffered = false,
OStreamKind K = OStreamKind::OK_OStream)
: Kind(K), BufferMode(unbuffered ? BufferKind::Unbuffered
: BufferKind::InternalBuffer) {
// Start out ready to flush.
OutBufStart = OutBufEnd = OutBufCur = nullptr;
}
@@ -93,10 +125,19 @@ public:
/// tell - Return the current offset with the file.
uint64_t tell() const { return current_pos() + GetNumBytesInBuffer(); }
OStreamKind get_kind() const { return Kind; }
//===--------------------------------------------------------------------===//
// Configuration Interface
//===--------------------------------------------------------------------===//
/// If possible, pre-allocate \p ExtraSize bytes for stream data.
/// i.e. it extends internal buffers to keep additional ExtraSize bytes.
/// So that the stream could keep at least tell() + ExtraSize bytes
/// without re-allocations. reserveExtraSpace() does not change
/// the size/data of the stream.
virtual void reserveExtraSpace(uint64_t ExtraSize) {}
/// Set the stream to be buffered, with an automatically determined buffer
/// size.
void SetBuffered();
@@ -104,13 +145,13 @@ public:
/// Set the stream to be buffered, using the specified buffer size.
void SetBufferSize(size_t Size) {
flush();
SetBufferAndMode(new char[Size], Size, InternalBuffer);
SetBufferAndMode(new char[Size], Size, BufferKind::InternalBuffer);
}
size_t GetBufferSize() const {
// If we're supposed to be buffered but haven't actually gotten around
// to allocating the buffer yet, return the value that would be used.
if (BufferMode != Unbuffered && OutBufStart == nullptr)
if (BufferMode != BufferKind::Unbuffered && OutBufStart == nullptr)
return preferred_buffer_size();
// Otherwise just return the size of the allocated buffer.
@@ -122,7 +163,7 @@ public:
/// when the stream is being set to unbuffered.
void SetUnbuffered() {
flush();
SetBufferAndMode(nullptr, 0, Unbuffered);
SetBufferAndMode(nullptr, 0, BufferKind::Unbuffered);
}
size_t GetNumBytesInBuffer() const {
@@ -237,9 +278,8 @@ public:
/// @param Bold bold/brighter text, default false
/// @param BG if true change the background, default: change foreground
/// @returns itself so it can be used within << invocations
virtual raw_ostream &changeColor(enum Colors Color,
bool Bold = false,
bool BG = false) {
virtual raw_ostream &changeColor(enum Colors Color, bool Bold = false,
bool BG = false) {
(void)Color;
(void)Bold;
(void)BG;
@@ -259,8 +299,17 @@ public:
virtual bool is_displayed() const { return false; }
/// This function determines if this stream is displayed and supports colors.
/// The result is unaffected by calls to enable_color().
virtual bool has_colors() const { return is_displayed(); }
// Enable or disable colors. Once enable_colors(false) is called,
// changeColor() has no effect until enable_colors(true) is called.
virtual void enable_colors(bool /*enable*/) {}
/// Tie this stream to the specified stream. Replaces any existing tied-to
/// stream. Specifying a nullptr unties the stream.
void tie(raw_ostream *TieTo) { TiedStream = TieTo; }
//===--------------------------------------------------------------------===//
// Subclass Interface
//===--------------------------------------------------------------------===//
@@ -281,9 +330,6 @@ private:
/// \invariant { Size > 0 }
virtual void write_impl(const char *Ptr, size_t Size) = 0;
// An out of line virtual method to provide a home for the class vtable.
virtual void handle();
/// Return the current position within the stream, not counting the bytes
/// currently in the buffer.
virtual uint64_t current_pos() const = 0;
@@ -293,7 +339,7 @@ protected:
/// use only by subclasses which can arrange for the output to go directly
/// into the desired output buffer, instead of being copied on each flush.
void SetBuffer(char *BufferStart, size_t Size) {
SetBufferAndMode(BufferStart, Size, ExternalBuffer);
SetBufferAndMode(BufferStart, Size, BufferKind::ExternalBuffer);
}
/// Return an efficient buffer size for the underlying output mechanism.
@@ -318,9 +364,23 @@ private:
/// unused bytes in the buffer.
void copy_to_buffer(const char *Ptr, size_t Size);
/// Flush the tied-to stream (if present) and then write the required data.
void flush_tied_then_write(const char *Ptr, size_t Size);
virtual void anchor();
};
/// Call the appropriate insertion operator, given an rvalue reference to a
/// raw_ostream object and return a stream of the same type as the argument.
template <typename OStream, typename T>
std::enable_if_t<!std::is_reference<OStream>::value &&
std::is_base_of<raw_ostream, OStream>::value,
OStream &&>
operator<<(OStream &&OS, const T &Value) {
OS << Value;
return std::move(OS);
}
/// An abstract base class for streams implementations that also support a
/// pwrite operation. This is useful for code that can mostly stream out data,
/// but needs to patch in a header that needs to know the output size.
@@ -329,10 +389,11 @@ class raw_pwrite_stream : public raw_ostream {
void anchor() override;
public:
explicit raw_pwrite_stream(bool Unbuffered = false)
: raw_ostream(Unbuffered) {}
explicit raw_pwrite_stream(bool Unbuffered = false,
OStreamKind K = OStreamKind::OK_OStream)
: raw_ostream(Unbuffered, K) {}
void pwrite(const char *Ptr, size_t Size, uint64_t Offset) {
#ifndef NDBEBUG
#ifndef NDEBUG
uint64_t Pos = tell();
// /dev/null always reports a pos of 0, so we cannot perform this check
// in that case.
@@ -352,8 +413,7 @@ public:
class raw_fd_ostream : public raw_pwrite_stream {
int FD;
bool ShouldClose;
bool SupportsSeeking;
bool SupportsSeeking = false;
#ifdef _WIN32
/// True if this fd refers to a Windows console device. Mintty and other
@@ -363,7 +423,7 @@ class raw_fd_ostream : public raw_pwrite_stream {
std::error_code EC;
uint64_t pos;
uint64_t pos = 0;
/// See raw_ostream::write_impl.
void write_impl(const char *Ptr, size_t Size) override;
@@ -377,10 +437,17 @@ class raw_fd_ostream : public raw_pwrite_stream {
/// Determine an efficient buffer size.
size_t preferred_buffer_size() const override;
void anchor() override;
protected:
/// Set the flag indicating that an output error has been encountered.
void error_detected(std::error_code EC) { this->EC = EC; }
void anchor() override;
/// Return the file descriptor.
int get_fd() const { return FD; }
// Update the file position by increasing \p Delta.
void inc_pos(uint64_t Delta) { pos += Delta; }
public:
/// Open the specified file for writing. If an error occurs, information
@@ -405,7 +472,8 @@ public:
/// FD is the file descriptor that this writes to. If ShouldClose is true,
/// this closes the file when the stream is destroyed. If FD is for stdout or
/// stderr, it will not be closed.
raw_fd_ostream(int fd, bool shouldClose, bool unbuffered=false);
raw_fd_ostream(int fd, bool shouldClose, bool unbuffered = false,
OStreamKind K = OStreamKind::OK_OStream);
~raw_fd_ostream() override;
@@ -413,7 +481,7 @@ public:
/// fsync.
void close();
bool supportsSeeking() { return SupportsSeeking; }
bool supportsSeeking() const { return SupportsSeeking; }
/// Flushes the stream and repositions the underlying file descriptor position
/// to the offset specified from the beginning of the file.
@@ -439,17 +507,37 @@ public:
void clear_error() { EC = std::error_code(); }
};
/// This returns a reference to a raw_ostream for standard output. Use it like:
/// outs() << "foo" << "bar";
raw_ostream &outs();
/// This returns a reference to a raw_fd_ostream for standard output. Use it
/// like: outs() << "foo" << "bar";
raw_fd_ostream &outs();
/// This returns a reference to a raw_ostream for standard error. Use it like:
/// errs() << "foo" << "bar";
raw_ostream &errs();
/// This returns a reference to a raw_ostream for standard error.
/// Use it like: errs() << "foo" << "bar";
/// By default, the stream is tied to stdout to ensure stdout is flushed before
/// stderr is written, to ensure the error messages are written in their
/// expected place.
raw_fd_ostream &errs();
/// This returns a reference to a raw_ostream which simply discards output.
raw_ostream &nulls();
//===----------------------------------------------------------------------===//
// File Streams
//===----------------------------------------------------------------------===//
/// A raw_ostream of a file for reading/writing/seeking.
///
class raw_fd_stream : public raw_fd_ostream {
public:
/// Open the specified file for reading/writing/seeking. If an error occurs,
/// information about the error is put into EC, and the stream should be
/// immediately destroyed.
raw_fd_stream(std::string_view Filename, std::error_code &EC);
/// Check if \p OS is a pointer of type raw_fd_stream*.
static bool classof(const raw_ostream *OS);
};
//===----------------------------------------------------------------------===//
// Output Stream Adaptors
//===----------------------------------------------------------------------===//
@@ -467,7 +555,9 @@ class raw_string_ostream : public raw_ostream {
uint64_t current_pos() const override { return OS.size(); }
public:
explicit raw_string_ostream(std::string &O) : OS(O) {}
explicit raw_string_ostream(std::string &O) : OS(O) {
SetUnbuffered();
}
~raw_string_ostream() override;
/// Flushes the stream contents to the target string and returns the string's
@@ -476,6 +566,10 @@ public:
flush();
return OS;
}
void reserveExtraSpace(uint64_t ExtraSize) override {
OS.reserve(tell() + ExtraSize);
}
};
/// A raw_ostream that writes to an SmallVector or SmallString. This is a
@@ -508,7 +602,11 @@ public:
void flush() = delete;
/// Return a std::string_view for the vector contents.
std::string_view str() { return std::string_view(OS.data(), OS.size()); }
std::string_view str() const { return std::string_view(OS.data(), OS.size()); }
void reserveExtraSpace(uint64_t ExtraSize) override {
OS.reserve(tell() + ExtraSize);
}
};
/// A raw_ostream that writes to a vector. This is a
@@ -639,6 +737,18 @@ public:
~buffer_ostream() override { OS << str(); }
};
class buffer_unique_ostream : public raw_svector_ostream {
std::unique_ptr<raw_ostream> OS;
SmallVector<char, 0> Buffer;
virtual void anchor() override;
public:
buffer_unique_ostream(std::unique_ptr<raw_ostream> OS)
: raw_svector_ostream(Buffer), OS(std::move(OS)) {}
~buffer_unique_ostream() override { *OS << str(); }
};
} // end namespace wpi
#endif // LLVM_SUPPORT_RAW_OSTREAM_H
#endif // WPIUTIL_WPI_RAW_OSTREAM_H

View File

@@ -1,9 +1,8 @@
//===- llvm/Support/type_traits.h - Simplfied type traits -------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -18,41 +17,8 @@
#include <type_traits>
#include <utility>
#ifndef __has_feature
#define WPI_DEFINED_HAS_FEATURE
#define __has_feature(x) 0
#endif
namespace wpi {
/// isPodLike - This is a type trait that is used to determine whether a given
/// type can be copied around with memcpy instead of running ctors etc.
template <typename T>
struct isPodLike {
// std::is_trivially_copyable is available in libc++ with clang, libstdc++
// that comes with GCC 5.
#if (__has_feature(is_trivially_copyable) && defined(_LIBCPP_VERSION)) || \
(defined(__GNUC__) && __GNUC__ >= 5)
// If the compiler supports the is_trivially_copyable trait use it, as it
// matches the definition of isPodLike closely.
static const bool value = std::is_trivially_copyable<T>::value;
#elif __has_feature(is_trivially_copyable)
// Use the internal name if the compiler supports is_trivially_copyable but we
// don't know if the standard library does. This is the case for clang in
// conjunction with libstdc++ from GCC 4.x.
static const bool value = __is_trivially_copyable(T);
#else
// If we don't know anything else, we can (at least) assume that all non-class
// types are PODs.
static const bool value = !std::is_class<T>::value;
#endif
};
// std::pair's are pod-like if their elements are.
template<typename T, typename U>
struct isPodLike<std::pair<T, U>> {
static const bool value = isPodLike<T>::value && isPodLike<U>::value;
};
/// Metafunction that determines whether the given type is either an
/// integral type or an enumeration type, including enum classes.
@@ -62,7 +28,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 {
using UnderlyingT = typename std::remove_reference<T>::type;
using UnderlyingT = std::remove_reference_t<T>;
public:
static const bool value =
@@ -79,7 +45,7 @@ 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> {
T, std::enable_if_t<std::is_pointer<T>::value>> {
using type = T;
};
@@ -89,9 +55,8 @@ template<typename T, typename Enable = void>
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> {
using type = const typename std::remove_pointer<T>::type *;
struct add_const_past_pointer<T, std::enable_if_t<std::is_pointer<T>::value>> {
using type = const std::remove_pointer_t<T> *;
};
template <typename T, typename Enable = void>
@@ -99,27 +64,41 @@ 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> {
struct const_pointer_or_const_ref<T,
std::enable_if_t<std::is_pointer<T>::value>> {
using type = typename add_const_past_pointer<T>::type;
};
} // namespace wpi
namespace detail {
/// Internal utility to detect trivial copy construction.
template<typename T> union copy_construction_triviality_helper {
T t;
copy_construction_triviality_helper() = default;
copy_construction_triviality_helper(const copy_construction_triviality_helper&) = default;
~copy_construction_triviality_helper() = default;
};
/// Internal utility to detect trivial move construction.
template<typename T> union move_construction_triviality_helper {
T t;
move_construction_triviality_helper() = default;
move_construction_triviality_helper(move_construction_triviality_helper&&) = default;
~move_construction_triviality_helper() = default;
};
// 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
template<class T>
union trivial_helper {
T t;
};
#ifdef WPI_DEFINED_HAS_FEATURE
#undef __has_feature
#undef WPI_DEFINED_HAS_FEATURE
#endif
} // end namespace detail
#endif // LLVM_SUPPORT_TYPE_TRAITS_H
template <typename T>
using is_trivially_move_constructible = std::is_trivially_move_constructible<T>;
template <typename T>
using is_trivially_copy_constructible = std::is_trivially_copy_constructible<T>;
} // end namespace wpi
#endif // WPIUTIL_WPI_TYPE_TRAITS_H