mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-28 02:11:43 +00:00
[wpiutil] Vendor llvm and update to 13.0.0 (#4224)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 &&
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
82
wpiutil/src/main/native/include/wpi/STLForwardCompat.h
Normal file
82
wpiutil/src/main/native/include/wpi/STLForwardCompat.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
143
wpiutil/src/main/native/include/wpi/StringMapEntry.h
Normal file
143
wpiutil/src/main/native/include/wpi/StringMapEntry.h
Normal 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
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user