mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-07-02 02:51:42 +00:00
@@ -99,6 +99,28 @@ public:
|
||||
void PrintStats() const {}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename Alloc> class AllocatorHolder : Alloc {
|
||||
public:
|
||||
AllocatorHolder() = default;
|
||||
AllocatorHolder(const Alloc &A) : Alloc(A) {}
|
||||
AllocatorHolder(Alloc &&A) : Alloc(static_cast<Alloc &&>(A)) {}
|
||||
Alloc &getAllocator() { return *this; }
|
||||
const Alloc &getAllocator() const { return *this; }
|
||||
};
|
||||
|
||||
template <typename Alloc> class AllocatorHolder<Alloc &> {
|
||||
Alloc &A;
|
||||
|
||||
public:
|
||||
AllocatorHolder(Alloc &A) : A(A) {}
|
||||
Alloc &getAllocator() { return A; }
|
||||
const Alloc &getAllocator() const { return A; }
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_ALLOCATORBASE_H
|
||||
|
||||
808
wpiutil/src/main/native/thirdparty/llvm/include/wpi/Casting.h
vendored
Normal file
808
wpiutil/src/main/native/thirdparty/llvm/include/wpi/Casting.h
vendored
Normal file
@@ -0,0 +1,808 @@
|
||||
//===- llvm/Support/Casting.h - Allow flexible, checked, casts --*- 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 isa<X>(), cast<X>(), dyn_cast<X>(),
|
||||
// cast_if_present<X>(), and dyn_cast_if_present<X>() templates.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_CASTING_H
|
||||
#define WPIUTIL_WPI_CASTING_H
|
||||
|
||||
#include "wpi/Compiler.h"
|
||||
#include "wpi/type_traits.h"
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// simplify_type
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Define a template that can be specialized by smart pointers to reflect the
|
||||
/// fact that they are automatically dereferenced, and are not involved with the
|
||||
/// template selection process... the default implementation is a noop.
|
||||
// TODO: rename this and/or replace it with other cast traits.
|
||||
template <typename From> struct simplify_type {
|
||||
using SimpleType = From; // The real type this represents...
|
||||
|
||||
// An accessor to get the real value...
|
||||
static SimpleType &getSimplifiedValue(From &Val) { return Val; }
|
||||
};
|
||||
|
||||
template <typename From> struct simplify_type<const From> {
|
||||
using NonConstSimpleType = typename simplify_type<From>::SimpleType;
|
||||
using SimpleType = typename add_const_past_pointer<NonConstSimpleType>::type;
|
||||
using RetType =
|
||||
typename add_lvalue_reference_if_not_pointer<SimpleType>::type;
|
||||
|
||||
static RetType getSimplifiedValue(const From &Val) {
|
||||
return simplify_type<From>::getSimplifiedValue(const_cast<From &>(Val));
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: add this namespace once everyone is switched to using the new
|
||||
// interface.
|
||||
// namespace detail {
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// isa_impl
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// The core of the implementation of isa<X> is here; To and From should be
|
||||
// the names of classes. This template can be specialized to customize the
|
||||
// implementation of isa<> without rewriting it from scratch.
|
||||
template <typename To, typename From, typename Enabler = void> struct isa_impl {
|
||||
static inline bool doit(const From &Val) { return To::classof(&Val); }
|
||||
};
|
||||
|
||||
// Always allow upcasts, and perform no dynamic check for them.
|
||||
template <typename To, typename From>
|
||||
struct isa_impl<To, From, std::enable_if_t<std::is_base_of<To, From>::value>> {
|
||||
static inline bool doit(const From &) { return true; }
|
||||
};
|
||||
|
||||
template <typename To, typename From> struct isa_impl_cl {
|
||||
static inline bool doit(const From &Val) {
|
||||
return isa_impl<To, From>::doit(Val);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename To, typename From> struct isa_impl_cl<To, const From> {
|
||||
static inline bool doit(const From &Val) {
|
||||
return isa_impl<To, From>::doit(Val);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename To, typename From>
|
||||
struct isa_impl_cl<To, const std::unique_ptr<From>> {
|
||||
static inline bool doit(const std::unique_ptr<From> &Val) {
|
||||
assert(Val && "isa<> used on a null pointer");
|
||||
return isa_impl_cl<To, From>::doit(*Val);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename To, typename From> struct isa_impl_cl<To, From *> {
|
||||
static inline bool doit(const From *Val) {
|
||||
assert(Val && "isa<> used on a null pointer");
|
||||
return isa_impl<To, From>::doit(*Val);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename To, typename From> struct isa_impl_cl<To, From *const> {
|
||||
static inline bool doit(const From *Val) {
|
||||
assert(Val && "isa<> used on a null pointer");
|
||||
return isa_impl<To, From>::doit(*Val);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename To, typename From> struct isa_impl_cl<To, const From *> {
|
||||
static inline bool doit(const From *Val) {
|
||||
assert(Val && "isa<> used on a null pointer");
|
||||
return isa_impl<To, From>::doit(*Val);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename To, typename From>
|
||||
struct isa_impl_cl<To, const From *const> {
|
||||
static inline bool doit(const From *Val) {
|
||||
assert(Val && "isa<> used on a null pointer");
|
||||
return isa_impl<To, From>::doit(*Val);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename To, typename From, typename SimpleFrom>
|
||||
struct isa_impl_wrap {
|
||||
// When From != SimplifiedType, we can simplify the type some more by using
|
||||
// the simplify_type template.
|
||||
static bool doit(const From &Val) {
|
||||
return isa_impl_wrap<To, SimpleFrom,
|
||||
typename simplify_type<SimpleFrom>::SimpleType>::
|
||||
doit(simplify_type<const From>::getSimplifiedValue(Val));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename To, typename FromTy>
|
||||
struct isa_impl_wrap<To, FromTy, FromTy> {
|
||||
// When From == SimpleType, we are as simple as we are going to get.
|
||||
static bool doit(const FromTy &Val) {
|
||||
return isa_impl_cl<To, FromTy>::doit(Val);
|
||||
}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// cast_retty + cast_retty_impl
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
template <class To, class From> struct cast_retty;
|
||||
|
||||
// Calculate what type the 'cast' function should return, based on a requested
|
||||
// type of To and a source type of From.
|
||||
template <class To, class From> struct cast_retty_impl {
|
||||
using ret_type = To &; // Normal case, return Ty&
|
||||
};
|
||||
template <class To, class From> struct cast_retty_impl<To, const From> {
|
||||
using ret_type = const To &; // Normal case, return Ty&
|
||||
};
|
||||
|
||||
template <class To, class From> struct cast_retty_impl<To, From *> {
|
||||
using ret_type = To *; // Pointer arg case, return Ty*
|
||||
};
|
||||
|
||||
template <class To, class From> struct cast_retty_impl<To, const From *> {
|
||||
using ret_type = const To *; // Constant pointer arg case, return const Ty*
|
||||
};
|
||||
|
||||
template <class To, class From> struct cast_retty_impl<To, const From *const> {
|
||||
using ret_type = const To *; // Constant pointer arg case, return const Ty*
|
||||
};
|
||||
|
||||
template <class To, class From>
|
||||
struct cast_retty_impl<To, std::unique_ptr<From>> {
|
||||
private:
|
||||
using PointerType = typename cast_retty_impl<To, From *>::ret_type;
|
||||
using ResultType = std::remove_pointer_t<PointerType>;
|
||||
|
||||
public:
|
||||
using ret_type = std::unique_ptr<ResultType>;
|
||||
};
|
||||
|
||||
template <class To, class From, class SimpleFrom> struct cast_retty_wrap {
|
||||
// When the simplified type and the from type are not the same, use the type
|
||||
// simplifier to reduce the type, then reuse cast_retty_impl to get the
|
||||
// resultant type.
|
||||
using ret_type = typename cast_retty<To, SimpleFrom>::ret_type;
|
||||
};
|
||||
|
||||
template <class To, class FromTy> struct cast_retty_wrap<To, FromTy, FromTy> {
|
||||
// When the simplified type is equal to the from type, use it directly.
|
||||
using ret_type = typename cast_retty_impl<To, FromTy>::ret_type;
|
||||
};
|
||||
|
||||
template <class To, class From> struct cast_retty {
|
||||
using ret_type = typename cast_retty_wrap<
|
||||
To, From, typename simplify_type<From>::SimpleType>::ret_type;
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// cast_convert_val
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Ensure the non-simple values are converted using the simplify_type template
|
||||
// that may be specialized by smart pointers...
|
||||
//
|
||||
template <class To, class From, class SimpleFrom> struct cast_convert_val {
|
||||
// This is not a simple type, use the template to simplify it...
|
||||
static typename cast_retty<To, From>::ret_type doit(const From &Val) {
|
||||
return cast_convert_val<To, SimpleFrom,
|
||||
typename simplify_type<SimpleFrom>::SimpleType>::
|
||||
doit(simplify_type<From>::getSimplifiedValue(const_cast<From &>(Val)));
|
||||
}
|
||||
};
|
||||
|
||||
template <class To, class FromTy> struct cast_convert_val<To, FromTy, FromTy> {
|
||||
// If it's a reference, switch to a pointer to do the cast and then deref it.
|
||||
static typename cast_retty<To, FromTy>::ret_type doit(const FromTy &Val) {
|
||||
return *(std::remove_reference_t<typename cast_retty<To, FromTy>::ret_type>
|
||||
*)&const_cast<FromTy &>(Val);
|
||||
}
|
||||
};
|
||||
|
||||
template <class To, class FromTy>
|
||||
struct cast_convert_val<To, FromTy *, FromTy *> {
|
||||
// If it's a pointer, we can use c-style casting directly.
|
||||
static typename cast_retty<To, FromTy *>::ret_type doit(const FromTy *Val) {
|
||||
return (typename cast_retty<To, FromTy *>::ret_type) const_cast<FromTy *>(
|
||||
Val);
|
||||
}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// is_simple_type
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
template <class X> struct is_simple_type {
|
||||
static const bool value =
|
||||
std::is_same<X, typename simplify_type<X>::SimpleType>::value;
|
||||
};
|
||||
|
||||
// } // namespace detail
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CastIsPossible
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// This struct provides a way to check if a given cast is possible. It provides
|
||||
/// a static function called isPossible that is used to check if a cast can be
|
||||
/// performed. It should be overridden like this:
|
||||
///
|
||||
/// template<> struct CastIsPossible<foo, bar> {
|
||||
/// static inline bool isPossible(const bar &b) {
|
||||
/// return bar.isFoo();
|
||||
/// }
|
||||
/// };
|
||||
template <typename To, typename From, typename Enable = void>
|
||||
struct CastIsPossible {
|
||||
static inline bool isPossible(const From &f) {
|
||||
return isa_impl_wrap<
|
||||
To, const From,
|
||||
typename simplify_type<const From>::SimpleType>::doit(f);
|
||||
}
|
||||
};
|
||||
|
||||
// Needed for optional unwrapping. This could be implemented with isa_impl, but
|
||||
// we want to implement things in the new method and move old implementations
|
||||
// over. In fact, some of the isa_impl templates should be moved over to
|
||||
// CastIsPossible.
|
||||
template <typename To, typename From>
|
||||
struct CastIsPossible<To, std::optional<From>> {
|
||||
static inline bool isPossible(const std::optional<From> &f) {
|
||||
assert(f && "CastIsPossible::isPossible called on a nullopt!");
|
||||
return isa_impl_wrap<
|
||||
To, const From,
|
||||
typename simplify_type<const From>::SimpleType>::doit(*f);
|
||||
}
|
||||
};
|
||||
|
||||
/// Upcasting (from derived to base) and casting from a type to itself should
|
||||
/// always be possible.
|
||||
template <typename To, typename From>
|
||||
struct CastIsPossible<To, From,
|
||||
std::enable_if_t<std::is_base_of<To, From>::value>> {
|
||||
static inline bool isPossible(const From &f) { return true; }
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Cast traits
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// All of these cast traits are meant to be implementations for useful casts
|
||||
/// that users may want to use that are outside the standard behavior. An
|
||||
/// example of how to use a special cast called `CastTrait` is:
|
||||
///
|
||||
/// template<> struct CastInfo<foo, bar> : public CastTrait<foo, bar> {};
|
||||
///
|
||||
/// Essentially, if your use case falls directly into one of the use cases
|
||||
/// supported by a given cast trait, simply inherit your special CastInfo
|
||||
/// directly from one of these to avoid having to reimplement the boilerplate
|
||||
/// `isPossible/castFailed/doCast/doCastIfPossible`. A cast trait can also
|
||||
/// provide a subset of those functions.
|
||||
|
||||
/// This cast trait just provides castFailed for the specified `To` type to make
|
||||
/// CastInfo specializations more declarative. In order to use this, the target
|
||||
/// result type must be `To` and `To` must be constructible from `nullptr`.
|
||||
template <typename To> struct NullableValueCastFailed {
|
||||
static To castFailed() { return To(nullptr); }
|
||||
};
|
||||
|
||||
/// This cast trait just provides the default implementation of doCastIfPossible
|
||||
/// to make CastInfo specializations more declarative. The `Derived` template
|
||||
/// parameter *must* be provided for forwarding castFailed and doCast.
|
||||
template <typename To, typename From, typename Derived>
|
||||
struct DefaultDoCastIfPossible {
|
||||
static To doCastIfPossible(From f) {
|
||||
if (!Derived::isPossible(f))
|
||||
return Derived::castFailed();
|
||||
return Derived::doCast(f);
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
/// A helper to derive the type to use with `Self` for cast traits, when the
|
||||
/// provided CRTP derived type is allowed to be void.
|
||||
template <typename OptionalDerived, typename Default>
|
||||
using SelfType = std::conditional_t<std::is_same<OptionalDerived, void>::value,
|
||||
Default, OptionalDerived>;
|
||||
} // namespace detail
|
||||
|
||||
/// This cast trait provides casting for the specific case of casting to a
|
||||
/// value-typed object from a pointer-typed object. Note that `To` must be
|
||||
/// nullable/constructible from a pointer to `From` to use this cast.
|
||||
template <typename To, typename From, typename Derived = void>
|
||||
struct ValueFromPointerCast
|
||||
: public CastIsPossible<To, From *>,
|
||||
public NullableValueCastFailed<To>,
|
||||
public DefaultDoCastIfPossible<
|
||||
To, From *,
|
||||
detail::SelfType<Derived, ValueFromPointerCast<To, From>>> {
|
||||
static inline To doCast(From *f) { return To(f); }
|
||||
};
|
||||
|
||||
/// This cast trait provides std::unique_ptr casting. It has the semantics of
|
||||
/// moving the contents of the input unique_ptr into the output unique_ptr
|
||||
/// during the cast. It's also a good example of how to implement a move-only
|
||||
/// cast.
|
||||
template <typename To, typename From, typename Derived = void>
|
||||
struct UniquePtrCast : public CastIsPossible<To, From *> {
|
||||
using Self = detail::SelfType<Derived, UniquePtrCast<To, From>>;
|
||||
using CastResultType = std::unique_ptr<
|
||||
std::remove_reference_t<typename cast_retty<To, From>::ret_type>>;
|
||||
|
||||
static inline CastResultType doCast(std::unique_ptr<From> &&f) {
|
||||
return CastResultType((typename CastResultType::element_type *)f.release());
|
||||
}
|
||||
|
||||
static inline CastResultType castFailed() { return CastResultType(nullptr); }
|
||||
|
||||
static inline CastResultType doCastIfPossible(std::unique_ptr<From> &&f) {
|
||||
if (!Self::isPossible(f))
|
||||
return castFailed();
|
||||
return doCast(f);
|
||||
}
|
||||
};
|
||||
|
||||
/// This cast trait provides std::optional<T> casting. This means that if you
|
||||
/// have a value type, you can cast it to another value type and have dyn_cast
|
||||
/// return an std::optional<T>.
|
||||
template <typename To, typename From, typename Derived = void>
|
||||
struct OptionalValueCast
|
||||
: public CastIsPossible<To, From>,
|
||||
public DefaultDoCastIfPossible<
|
||||
std::optional<To>, From,
|
||||
detail::SelfType<Derived, OptionalValueCast<To, From>>> {
|
||||
static inline std::optional<To> castFailed() { return std::optional<To>{}; }
|
||||
|
||||
static inline std::optional<To> doCast(const From &f) { return To(f); }
|
||||
};
|
||||
|
||||
/// Provides a cast trait that strips `const` from types to make it easier to
|
||||
/// implement a const-version of a non-const cast. It just removes boilerplate
|
||||
/// and reduces the amount of code you as the user need to implement. You can
|
||||
/// use it like this:
|
||||
///
|
||||
/// template<> struct CastInfo<foo, bar> {
|
||||
/// ...verbose implementation...
|
||||
/// };
|
||||
///
|
||||
/// template<> struct CastInfo<foo, const bar> : public
|
||||
/// ConstStrippingForwardingCast<foo, const bar, CastInfo<foo, bar>> {};
|
||||
///
|
||||
template <typename To, typename From, typename ForwardTo>
|
||||
struct ConstStrippingForwardingCast {
|
||||
// Remove the pointer if it exists, then we can get rid of consts/volatiles.
|
||||
using DecayedFrom = std::remove_cv_t<std::remove_pointer_t<From>>;
|
||||
// Now if it's a pointer, add it back. Otherwise, we want a ref.
|
||||
using NonConstFrom = std::conditional_t<std::is_pointer<From>::value,
|
||||
DecayedFrom *, DecayedFrom &>;
|
||||
|
||||
static inline bool isPossible(const From &f) {
|
||||
return ForwardTo::isPossible(const_cast<NonConstFrom>(f));
|
||||
}
|
||||
|
||||
static inline decltype(auto) castFailed() { return ForwardTo::castFailed(); }
|
||||
|
||||
static inline decltype(auto) doCast(const From &f) {
|
||||
return ForwardTo::doCast(const_cast<NonConstFrom>(f));
|
||||
}
|
||||
|
||||
static inline decltype(auto) doCastIfPossible(const From &f) {
|
||||
return ForwardTo::doCastIfPossible(const_cast<NonConstFrom>(f));
|
||||
}
|
||||
};
|
||||
|
||||
/// Provides a cast trait that uses a defined pointer to pointer cast as a base
|
||||
/// for reference-to-reference casts. Note that it does not provide castFailed
|
||||
/// and doCastIfPossible because a pointer-to-pointer cast would likely just
|
||||
/// return `nullptr` which could cause nullptr dereference. You can use it like
|
||||
/// this:
|
||||
///
|
||||
/// template <> struct CastInfo<foo, bar *> { ... verbose implementation... };
|
||||
///
|
||||
/// template <>
|
||||
/// struct CastInfo<foo, bar>
|
||||
/// : public ForwardToPointerCast<foo, bar, CastInfo<foo, bar *>> {};
|
||||
///
|
||||
template <typename To, typename From, typename ForwardTo>
|
||||
struct ForwardToPointerCast {
|
||||
static inline bool isPossible(const From &f) {
|
||||
return ForwardTo::isPossible(&f);
|
||||
}
|
||||
|
||||
static inline decltype(auto) doCast(const From &f) {
|
||||
return *ForwardTo::doCast(&f);
|
||||
}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CastInfo
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// This struct provides a method for customizing the way a cast is performed.
|
||||
/// It inherits from CastIsPossible, to support the case of declaring many
|
||||
/// CastIsPossible specializations without having to specialize the full
|
||||
/// CastInfo.
|
||||
///
|
||||
/// In order to specialize different behaviors, specify different functions in
|
||||
/// your CastInfo specialization.
|
||||
/// For isa<> customization, provide:
|
||||
///
|
||||
/// `static bool isPossible(const From &f)`
|
||||
///
|
||||
/// For cast<> customization, provide:
|
||||
///
|
||||
/// `static To doCast(const From &f)`
|
||||
///
|
||||
/// For dyn_cast<> and the *_if_present<> variants' customization, provide:
|
||||
///
|
||||
/// `static To castFailed()` and `static To doCastIfPossible(const From &f)`
|
||||
///
|
||||
/// Your specialization might look something like this:
|
||||
///
|
||||
/// template<> struct CastInfo<foo, bar> : public CastIsPossible<foo, bar> {
|
||||
/// static inline foo doCast(const bar &b) {
|
||||
/// return foo(const_cast<bar &>(b));
|
||||
/// }
|
||||
/// static inline foo castFailed() { return foo(); }
|
||||
/// static inline foo doCastIfPossible(const bar &b) {
|
||||
/// if (!CastInfo<foo, bar>::isPossible(b))
|
||||
/// return castFailed();
|
||||
/// return doCast(b);
|
||||
/// }
|
||||
/// };
|
||||
|
||||
// The default implementations of CastInfo don't use cast traits for now because
|
||||
// we need to specify types all over the place due to the current expected
|
||||
// casting behavior and the way cast_retty works. New use cases can and should
|
||||
// take advantage of the cast traits whenever possible!
|
||||
|
||||
template <typename To, typename From, typename Enable = void>
|
||||
struct CastInfo : public CastIsPossible<To, From> {
|
||||
using Self = CastInfo<To, From, Enable>;
|
||||
|
||||
using CastReturnType = typename cast_retty<To, From>::ret_type;
|
||||
|
||||
static inline CastReturnType doCast(const From &f) {
|
||||
return cast_convert_val<
|
||||
To, From,
|
||||
typename simplify_type<From>::SimpleType>::doit(const_cast<From &>(f));
|
||||
}
|
||||
|
||||
// This assumes that you can construct the cast return type from `nullptr`.
|
||||
// This is largely to support legacy use cases - if you don't want this
|
||||
// behavior you should specialize CastInfo for your use case.
|
||||
static inline CastReturnType castFailed() { return CastReturnType(nullptr); }
|
||||
|
||||
static inline CastReturnType doCastIfPossible(const From &f) {
|
||||
if (!Self::isPossible(f))
|
||||
return castFailed();
|
||||
return doCast(f);
|
||||
}
|
||||
};
|
||||
|
||||
/// This struct provides an overload for CastInfo where From has simplify_type
|
||||
/// defined. This simply forwards to the appropriate CastInfo with the
|
||||
/// simplified type/value, so you don't have to implement both.
|
||||
template <typename To, typename From>
|
||||
struct CastInfo<To, From, std::enable_if_t<!is_simple_type<From>::value>> {
|
||||
using Self = CastInfo<To, From>;
|
||||
using SimpleFrom = typename simplify_type<From>::SimpleType;
|
||||
using SimplifiedSelf = CastInfo<To, SimpleFrom>;
|
||||
|
||||
static inline bool isPossible(From &f) {
|
||||
return SimplifiedSelf::isPossible(
|
||||
simplify_type<From>::getSimplifiedValue(f));
|
||||
}
|
||||
|
||||
static inline decltype(auto) doCast(From &f) {
|
||||
return SimplifiedSelf::doCast(simplify_type<From>::getSimplifiedValue(f));
|
||||
}
|
||||
|
||||
static inline decltype(auto) castFailed() {
|
||||
return SimplifiedSelf::castFailed();
|
||||
}
|
||||
|
||||
static inline decltype(auto) doCastIfPossible(From &f) {
|
||||
return SimplifiedSelf::doCastIfPossible(
|
||||
simplify_type<From>::getSimplifiedValue(f));
|
||||
}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Pre-specialized CastInfo
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Provide a CastInfo specialized for std::unique_ptr.
|
||||
template <typename To, typename From>
|
||||
struct CastInfo<To, std::unique_ptr<From>> : public UniquePtrCast<To, From> {};
|
||||
|
||||
/// Provide a CastInfo specialized for std::optional<From>. It's assumed that if
|
||||
/// the input is std::optional<From> that the output can be std::optional<To>.
|
||||
/// If that's not the case, specialize CastInfo for your use case.
|
||||
template <typename To, typename From>
|
||||
struct CastInfo<To, std::optional<From>> : public OptionalValueCast<To, From> {
|
||||
};
|
||||
|
||||
/// isa<X> - Return true if the parameter to the template is an instance of one
|
||||
/// of the template type arguments. Used like this:
|
||||
///
|
||||
/// if (isa<Type>(myVal)) { ... }
|
||||
/// if (isa<Type0, Type1, Type2>(myVal)) { ... }
|
||||
template <typename To, typename From>
|
||||
[[nodiscard]] inline bool isa(const From &Val) {
|
||||
return CastInfo<To, const From>::isPossible(Val);
|
||||
}
|
||||
|
||||
template <typename First, typename Second, typename... Rest, typename From>
|
||||
[[nodiscard]] inline bool isa(const From &Val) {
|
||||
return isa<First>(Val) || isa<Second, Rest...>(Val);
|
||||
}
|
||||
|
||||
/// cast<X> - Return the argument parameter cast to the specified type. This
|
||||
/// casting operator asserts that the type is correct, so it does not return
|
||||
/// null on failure. It does not allow a null argument (use cast_if_present for
|
||||
/// that). It is typically used like this:
|
||||
///
|
||||
/// cast<Instruction>(myVal)->getParent()
|
||||
|
||||
template <typename To, typename From>
|
||||
[[nodiscard]] inline decltype(auto) cast(const From &Val) {
|
||||
assert(isa<To>(Val) && "cast<Ty>() argument of incompatible type!");
|
||||
return CastInfo<To, const From>::doCast(Val);
|
||||
}
|
||||
|
||||
template <typename To, typename From>
|
||||
[[nodiscard]] inline decltype(auto) cast(From &Val) {
|
||||
assert(isa<To>(Val) && "cast<Ty>() argument of incompatible type!");
|
||||
return CastInfo<To, From>::doCast(Val);
|
||||
}
|
||||
|
||||
template <typename To, typename From>
|
||||
[[nodiscard]] inline decltype(auto) cast(From *Val) {
|
||||
assert(isa<To>(Val) && "cast<Ty>() argument of incompatible type!");
|
||||
return CastInfo<To, From *>::doCast(Val);
|
||||
}
|
||||
|
||||
template <typename To, typename From>
|
||||
[[nodiscard]] inline decltype(auto) cast(std::unique_ptr<From> &&Val) {
|
||||
assert(isa<To>(Val) && "cast<Ty>() argument of incompatible type!");
|
||||
return CastInfo<To, std::unique_ptr<From>>::doCast(std::move(Val));
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ValueIsPresent
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
template <typename T>
|
||||
constexpr bool IsNullable =
|
||||
std::is_pointer_v<T> || std::is_constructible_v<T, std::nullptr_t>;
|
||||
|
||||
/// ValueIsPresent provides a way to check if a value is, well, present. For
|
||||
/// pointers, this is the equivalent of checking against nullptr, for Optionals
|
||||
/// this is the equivalent of checking hasValue(). It also provides a method for
|
||||
/// unwrapping a value (think calling .value() on an optional).
|
||||
|
||||
// Generic values can't *not* be present.
|
||||
template <typename T, typename Enable = void> struct ValueIsPresent {
|
||||
using UnwrappedType = T;
|
||||
static inline bool isPresent(const T &t) { return true; }
|
||||
static inline decltype(auto) unwrapValue(T &t) { return t; }
|
||||
};
|
||||
|
||||
// Optional provides its own way to check if something is present.
|
||||
template <typename T> struct ValueIsPresent<std::optional<T>> {
|
||||
using UnwrappedType = T;
|
||||
static inline bool isPresent(const std::optional<T> &t) {
|
||||
return t.has_value();
|
||||
}
|
||||
static inline decltype(auto) unwrapValue(std::optional<T> &t) { return *t; }
|
||||
};
|
||||
|
||||
// If something is "nullable" then we just compare it to nullptr to see if it
|
||||
// exists.
|
||||
template <typename T>
|
||||
struct ValueIsPresent<T, std::enable_if_t<IsNullable<T>>> {
|
||||
using UnwrappedType = T;
|
||||
static inline bool isPresent(const T &t) { return t != T(nullptr); }
|
||||
static inline decltype(auto) unwrapValue(T &t) { return t; }
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
// Convenience function we can use to check if a value is present. Because of
|
||||
// simplify_type, we have to call it on the simplified type for now.
|
||||
template <typename T> inline bool isPresent(const T &t) {
|
||||
return ValueIsPresent<typename simplify_type<T>::SimpleType>::isPresent(
|
||||
simplify_type<T>::getSimplifiedValue(const_cast<T &>(t)));
|
||||
}
|
||||
|
||||
// Convenience function we can use to unwrap a value.
|
||||
template <typename T> inline decltype(auto) unwrapValue(T &t) {
|
||||
return ValueIsPresent<T>::unwrapValue(t);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
/// dyn_cast<X> - Return the argument parameter cast to the specified type. This
|
||||
/// casting operator returns null if the argument is of the wrong type, so it
|
||||
/// can be used to test for a type as well as cast if successful. The value
|
||||
/// passed in must be present, if not, use dyn_cast_if_present. This should be
|
||||
/// used in the context of an if statement like this:
|
||||
///
|
||||
/// if (const Instruction *I = dyn_cast<Instruction>(myVal)) { ... }
|
||||
|
||||
template <typename To, typename From>
|
||||
[[nodiscard]] inline decltype(auto) dyn_cast(const From &Val) {
|
||||
assert(detail::isPresent(Val) && "dyn_cast on a non-existent value");
|
||||
return CastInfo<To, const From>::doCastIfPossible(Val);
|
||||
}
|
||||
|
||||
template <typename To, typename From>
|
||||
[[nodiscard]] inline decltype(auto) dyn_cast(From &Val) {
|
||||
assert(detail::isPresent(Val) && "dyn_cast on a non-existent value");
|
||||
return CastInfo<To, From>::doCastIfPossible(Val);
|
||||
}
|
||||
|
||||
template <typename To, typename From>
|
||||
[[nodiscard]] inline decltype(auto) dyn_cast(From *Val) {
|
||||
assert(detail::isPresent(Val) && "dyn_cast on a non-existent value");
|
||||
return CastInfo<To, From *>::doCastIfPossible(Val);
|
||||
}
|
||||
|
||||
template <typename To, typename From>
|
||||
[[nodiscard]] inline decltype(auto) dyn_cast(std::unique_ptr<From> &&Val) {
|
||||
assert(detail::isPresent(Val) && "dyn_cast on a non-existent value");
|
||||
return CastInfo<To, std::unique_ptr<From>>::doCastIfPossible(
|
||||
std::forward<std::unique_ptr<From> &&>(Val));
|
||||
}
|
||||
|
||||
/// isa_and_present<X> - Functionally identical to isa, except that a null value
|
||||
/// is accepted.
|
||||
template <typename... X, class Y>
|
||||
[[nodiscard]] inline bool isa_and_present(const Y &Val) {
|
||||
if (!detail::isPresent(Val))
|
||||
return false;
|
||||
return isa<X...>(Val);
|
||||
}
|
||||
|
||||
template <typename... X, class Y>
|
||||
[[nodiscard]] inline bool isa_and_nonnull(const Y &Val) {
|
||||
return isa_and_present<X...>(Val);
|
||||
}
|
||||
|
||||
/// cast_if_present<X> - Functionally identical to cast, except that a null
|
||||
/// value is accepted.
|
||||
template <class X, class Y>
|
||||
[[nodiscard]] inline auto cast_if_present(const Y &Val) {
|
||||
if (!detail::isPresent(Val))
|
||||
return CastInfo<X, const Y>::castFailed();
|
||||
assert(isa<X>(Val) && "cast_if_present<Ty>() argument of incompatible type!");
|
||||
return cast<X>(detail::unwrapValue(Val));
|
||||
}
|
||||
|
||||
template <class X, class Y> [[nodiscard]] inline auto cast_if_present(Y &Val) {
|
||||
if (!detail::isPresent(Val))
|
||||
return CastInfo<X, Y>::castFailed();
|
||||
assert(isa<X>(Val) && "cast_if_present<Ty>() argument of incompatible type!");
|
||||
return cast<X>(detail::unwrapValue(Val));
|
||||
}
|
||||
|
||||
template <class X, class Y> [[nodiscard]] inline auto cast_if_present(Y *Val) {
|
||||
if (!detail::isPresent(Val))
|
||||
return CastInfo<X, Y *>::castFailed();
|
||||
assert(isa<X>(Val) && "cast_if_present<Ty>() argument of incompatible type!");
|
||||
return cast<X>(detail::unwrapValue(Val));
|
||||
}
|
||||
|
||||
template <class X, class Y>
|
||||
[[nodiscard]] inline auto cast_if_present(std::unique_ptr<Y> &&Val) {
|
||||
if (!detail::isPresent(Val))
|
||||
return UniquePtrCast<X, Y>::castFailed();
|
||||
return UniquePtrCast<X, Y>::doCast(std::move(Val));
|
||||
}
|
||||
|
||||
// Provide a forwarding from cast_or_null to cast_if_present for current
|
||||
// users. This is deprecated and will be removed in a future patch, use
|
||||
// cast_if_present instead.
|
||||
template <class X, class Y> auto cast_or_null(const Y &Val) {
|
||||
return cast_if_present<X>(Val);
|
||||
}
|
||||
|
||||
template <class X, class Y> auto cast_or_null(Y &Val) {
|
||||
return cast_if_present<X>(Val);
|
||||
}
|
||||
|
||||
template <class X, class Y> auto cast_or_null(Y *Val) {
|
||||
return cast_if_present<X>(Val);
|
||||
}
|
||||
|
||||
template <class X, class Y> auto cast_or_null(std::unique_ptr<Y> &&Val) {
|
||||
return cast_if_present<X>(std::move(Val));
|
||||
}
|
||||
|
||||
/// dyn_cast_if_present<X> - Functionally identical to dyn_cast, except that a
|
||||
/// null (or none in the case of optionals) value is accepted.
|
||||
template <class X, class Y> auto dyn_cast_if_present(const Y &Val) {
|
||||
if (!detail::isPresent(Val))
|
||||
return CastInfo<X, const Y>::castFailed();
|
||||
return CastInfo<X, const Y>::doCastIfPossible(detail::unwrapValue(Val));
|
||||
}
|
||||
|
||||
template <class X, class Y> auto dyn_cast_if_present(Y &Val) {
|
||||
if (!detail::isPresent(Val))
|
||||
return CastInfo<X, Y>::castFailed();
|
||||
return CastInfo<X, Y>::doCastIfPossible(detail::unwrapValue(Val));
|
||||
}
|
||||
|
||||
template <class X, class Y> auto dyn_cast_if_present(Y *Val) {
|
||||
if (!detail::isPresent(Val))
|
||||
return CastInfo<X, Y *>::castFailed();
|
||||
return CastInfo<X, Y *>::doCastIfPossible(detail::unwrapValue(Val));
|
||||
}
|
||||
|
||||
// Forwards to dyn_cast_if_present to avoid breaking current users. This is
|
||||
// deprecated and will be removed in a future patch, use
|
||||
// cast_if_present instead.
|
||||
template <class X, class Y> auto dyn_cast_or_null(const Y &Val) {
|
||||
return dyn_cast_if_present<X>(Val);
|
||||
}
|
||||
|
||||
template <class X, class Y> auto dyn_cast_or_null(Y &Val) {
|
||||
return dyn_cast_if_present<X>(Val);
|
||||
}
|
||||
|
||||
template <class X, class Y> auto dyn_cast_or_null(Y *Val) {
|
||||
return dyn_cast_if_present<X>(Val);
|
||||
}
|
||||
|
||||
/// unique_dyn_cast<X> - Given a unique_ptr<Y>, try to return a unique_ptr<X>,
|
||||
/// taking ownership of the input pointer iff isa<X>(Val) is true. If the
|
||||
/// cast is successful, From refers to nullptr on exit and the casted value
|
||||
/// is returned. If the cast is unsuccessful, the function returns nullptr
|
||||
/// and From is unchanged.
|
||||
template <class X, class Y>
|
||||
[[nodiscard]] inline typename CastInfo<X, std::unique_ptr<Y>>::CastResultType
|
||||
unique_dyn_cast(std::unique_ptr<Y> &Val) {
|
||||
if (!isa<X>(Val))
|
||||
return nullptr;
|
||||
return cast<X>(std::move(Val));
|
||||
}
|
||||
|
||||
template <class X, class Y>
|
||||
[[nodiscard]] inline auto unique_dyn_cast(std::unique_ptr<Y> &&Val) {
|
||||
return unique_dyn_cast<X, Y>(Val);
|
||||
}
|
||||
|
||||
// unique_dyn_cast_or_null<X> - Functionally identical to unique_dyn_cast,
|
||||
// except that a null value is accepted.
|
||||
template <class X, class Y>
|
||||
[[nodiscard]] inline typename CastInfo<X, std::unique_ptr<Y>>::CastResultType
|
||||
unique_dyn_cast_or_null(std::unique_ptr<Y> &Val) {
|
||||
if (!Val)
|
||||
return nullptr;
|
||||
return unique_dyn_cast<X, Y>(Val);
|
||||
}
|
||||
|
||||
template <class X, class Y>
|
||||
[[nodiscard]] inline auto unique_dyn_cast_or_null(std::unique_ptr<Y> &&Val) {
|
||||
return unique_dyn_cast_or_null<X, Y>(Val);
|
||||
}
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_CASTING_H
|
||||
@@ -38,6 +38,10 @@
|
||||
# define __has_builtin(x) 0
|
||||
#endif
|
||||
|
||||
#ifndef __has_include
|
||||
# define __has_include(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
|
||||
@@ -101,26 +105,6 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// 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. This appears to be
|
||||
/// corrected in MSVC 2019 but not MSVC 2017.
|
||||
/// FIXME: Remove LLVM_HAS_RVALUE_REFERENCE_THIS macro
|
||||
#define LLVM_HAS_RVALUE_REFERENCE_THIS 1
|
||||
|
||||
/// Expands to '&' if ref-qualifiers for *this are supported.
|
||||
///
|
||||
/// This can be used to provide lvalue/rvalue overrides of member functions.
|
||||
/// The rvalue override should be guarded by LLVM_HAS_RVALUE_REFERENCE_THIS
|
||||
#ifndef LLVM_LVALUE_FUNCTION
|
||||
#if LLVM_HAS_RVALUE_REFERENCE_THIS
|
||||
#define LLVM_LVALUE_FUNCTION &
|
||||
#else
|
||||
#define LLVM_LVALUE_FUNCTION
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// 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
|
||||
@@ -130,8 +114,9 @@
|
||||
/// 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) && !defined(__MINGW32__) && \
|
||||
!defined(__CYGWIN__) && !defined(_WIN32)
|
||||
#if __has_attribute(visibility) && \
|
||||
(!(defined(_WIN32) || defined(__CYGWIN__)) || \
|
||||
(defined(__MINGW32__) && defined(__clang__)))
|
||||
#define LLVM_LIBRARY_VISIBILITY __attribute__ ((visibility("hidden")))
|
||||
#if defined(LLVM_BUILD_LLVM_DYLIB) || defined(LLVM_BUILD_SHARED_LIBS)
|
||||
#define LLVM_EXTERNAL_VISIBILITY __attribute__((visibility("default")))
|
||||
@@ -159,23 +144,10 @@
|
||||
#endif
|
||||
#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 defined(__cplusplus) && __cplusplus > 201402L && LLVM_HAS_CPP_ATTRIBUTE(nodiscard)
|
||||
#define LLVM_NODISCARD [[nodiscard]]
|
||||
#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]]
|
||||
#if defined(__clang__)
|
||||
#define LLVM_DEPRECATED(MSG, FIX) __attribute__((deprecated(MSG, FIX)))
|
||||
#else
|
||||
#define LLVM_NODISCARD
|
||||
#endif
|
||||
#define LLVM_DEPRECATED(MSG, FIX) [[deprecated(MSG)]]
|
||||
#endif
|
||||
|
||||
// Indicate that a non-static, non-const C++ member function reinitializes
|
||||
@@ -356,23 +328,18 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// LLVM_ATTRIBUTE_DEPRECATED(decl, "message")
|
||||
// This macro will be removed.
|
||||
// Use C++14's attribute instead: [[deprecated("message")]]
|
||||
#ifndef LLVM_ATTRIBUTE_DEPRECATED
|
||||
#define LLVM_ATTRIBUTE_DEPRECATED(decl, message) [[deprecated(message)]] decl
|
||||
#endif
|
||||
|
||||
/// LLVM_BUILTIN_UNREACHABLE - On compilers which support it, expands
|
||||
/// to an expression which states that it is undefined behavior for the
|
||||
/// compiler to reach this point. Otherwise is not defined.
|
||||
///
|
||||
/// '#else' is intentionally left out so that other macro logic (e.g.,
|
||||
/// LLVM_ASSUME_ALIGNED and wpi_unreachable()) can detect whether
|
||||
/// LLVM_BUILTIN_UNREACHABLE has a definition.
|
||||
#ifndef LLVM_BUILTIN_UNREACHABLE
|
||||
#if __has_builtin(__builtin_unreachable) || defined(__GNUC__)
|
||||
# define LLVM_BUILTIN_UNREACHABLE __builtin_unreachable()
|
||||
#elif defined(_MSC_VER)
|
||||
# define LLVM_BUILTIN_UNREACHABLE __assume(false)
|
||||
#else
|
||||
# define LLVM_BUILTIN_UNREACHABLE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -454,24 +421,6 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_PTR_SIZE
|
||||
/// A constant integer equivalent to the value of sizeof(void*).
|
||||
/// 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__
|
||||
#elif defined(_WIN64)
|
||||
# define LLVM_PTR_SIZE 8
|
||||
#elif defined(_WIN32)
|
||||
# define LLVM_PTR_SIZE 4
|
||||
#elif defined(_MSC_VER)
|
||||
# error "could not determine LLVM_PTR_SIZE as a constant int for MSVC"
|
||||
#else
|
||||
# define LLVM_PTR_SIZE sizeof(void *)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_MEMORY_SANITIZER_BUILD
|
||||
/// Whether LLVM itself is built with MemorySanitizer instrumentation.
|
||||
#if __has_feature(memory_sanitizer)
|
||||
@@ -489,13 +438,34 @@
|
||||
/// Whether LLVM itself is built with AddressSanitizer instrumentation.
|
||||
#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
|
||||
# define LLVM_ADDRESS_SANITIZER_BUILD 1
|
||||
#if __has_include(<sanitizer/asan_interface.h>)
|
||||
# include <sanitizer/asan_interface.h>
|
||||
#else
|
||||
// These declarations exist to support ASan with MSVC. If MSVC eventually ships
|
||||
// asan_interface.h in their headers, then we can remove this.
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void __asan_poison_memory_region(void const volatile *addr, size_t size);
|
||||
void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
# define LLVM_ADDRESS_SANITIZER_BUILD 0
|
||||
# define __asan_poison_memory_region(p, size)
|
||||
# define __asan_unpoison_memory_region(p, size)
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_HWADDRESS_SANITIZER_BUILD
|
||||
/// Whether LLVM itself is built with HWAddressSanitizer instrumentation.
|
||||
#if __has_feature(hwaddress_sanitizer)
|
||||
#define LLVM_HWADDRESS_SANITIZER_BUILD 1
|
||||
#else
|
||||
#define LLVM_HWADDRESS_SANITIZER_BUILD 0
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_THREAD_SANITIZER_BUILD
|
||||
/// Whether LLVM itself is built with ThreadSanitizer instrumentation.
|
||||
#if __has_feature(thread_sanitizer) || defined(__SANITIZE_THREAD__)
|
||||
|
||||
@@ -6,25 +6,41 @@
|
||||
*
|
||||
*==------------------------------------------------------------------------==*/
|
||||
/*
|
||||
* Copyright 2001-2004 Unicode, Inc.
|
||||
* Copyright © 1991-2015 Unicode, Inc. All rights reserved.
|
||||
* Distributed under the Terms of Use in
|
||||
* http://www.unicode.org/copyright.html.
|
||||
*
|
||||
* Disclaimer
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of the Unicode data files and any associated documentation
|
||||
* (the "Data Files") or Unicode software and any associated documentation
|
||||
* (the "Software") to deal in the Data Files or Software
|
||||
* without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, and/or sell copies of
|
||||
* the Data Files or Software, and to permit persons to whom the Data Files
|
||||
* or Software are furnished to do so, provided that
|
||||
* (a) this copyright and permission notice appear with all copies
|
||||
* of the Data Files or Software,
|
||||
* (b) this copyright and permission notice appear in associated
|
||||
* documentation, and
|
||||
* (c) there is clear notice in each modified Data File or in the Software
|
||||
* as well as in the documentation associated with the Data File(s) or
|
||||
* Software that the data or software has been modified.
|
||||
*
|
||||
* This source code is provided as is by Unicode, Inc. No claims are
|
||||
* made as to fitness for any particular purpose. No warranties of any
|
||||
* kind are expressed or implied. The recipient agrees to determine
|
||||
* applicability of information provided. If this file has been
|
||||
* purchased on magnetic or optical media from Unicode, Inc., the
|
||||
* sole remedy for any claim will be exchange of defective media
|
||||
* within 90 days of receipt.
|
||||
* THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
|
||||
* NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
|
||||
* DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THE DATA FILES OR SOFTWARE.
|
||||
*
|
||||
* Limitations on Rights to Redistribute This Code
|
||||
*
|
||||
* Unicode, Inc. hereby grants the right to freely use the information
|
||||
* supplied in this file in the creation of products supporting the
|
||||
* Unicode Standard, and to make copies of this file in any form
|
||||
* for internal or external distribution as long as this notice
|
||||
* remains attached.
|
||||
* Except as contained in this notice, the name of a copyright holder
|
||||
* shall not be used in advertising or otherwise to promote the sale,
|
||||
* use or other dealings in these Data Files or Software without prior
|
||||
* written authorization of the copyright holder.
|
||||
*/
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
@@ -89,10 +105,9 @@
|
||||
#ifndef WPIUTIL_WPI_CONVERTUTF_H
|
||||
#define WPIUTIL_WPI_CONVERTUTF_H
|
||||
|
||||
#include <span>
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <span>
|
||||
#include <string_view>
|
||||
#include <system_error>
|
||||
|
||||
@@ -126,6 +141,9 @@ typedef bool Boolean; /* 0 or 1 */
|
||||
#define UNI_UTF16_BYTE_ORDER_MARK_NATIVE 0xFEFF
|
||||
#define UNI_UTF16_BYTE_ORDER_MARK_SWAPPED 0xFFFE
|
||||
|
||||
#define UNI_UTF32_BYTE_ORDER_MARK_NATIVE 0x0000FEFF
|
||||
#define UNI_UTF32_BYTE_ORDER_MARK_SWAPPED 0xFFFE0000
|
||||
|
||||
typedef enum {
|
||||
conversionOK, /* conversion successful */
|
||||
sourceExhausted, /* partial character in source, but hit end */
|
||||
@@ -178,6 +196,8 @@ Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
|
||||
|
||||
Boolean isLegalUTF8String(const UTF8 **source, const UTF8 *sourceEnd);
|
||||
|
||||
unsigned getUTF8SequenceSize(const UTF8 *source, const UTF8 *sourceEnd);
|
||||
|
||||
unsigned getNumBytesForUTF8(UTF8 firstByte);
|
||||
|
||||
/*************************************************************************/
|
||||
@@ -279,6 +299,24 @@ bool convertUTF16ToUTF8String(std::span<const char> SrcBytes, SmallVectorImpl<ch
|
||||
*/
|
||||
bool convertUTF16ToUTF8String(std::span<const UTF16> Src, SmallVectorImpl<char> &Out);
|
||||
|
||||
/**
|
||||
* Converts a stream of raw bytes assumed to be UTF32 into a UTF8 std::string.
|
||||
*
|
||||
* \param [in] SrcBytes A buffer of what is assumed to be UTF-32 encoded text.
|
||||
* \param [out] Out Converted UTF-8 is stored here on success.
|
||||
* \returns true on success
|
||||
*/
|
||||
bool convertUTF32ToUTF8String(std::span<const char> SrcBytes, std::string &Out);
|
||||
|
||||
/**
|
||||
* Converts a UTF32 string into a UTF8 std::string.
|
||||
*
|
||||
* \param [in] Src A buffer of UTF-32 encoded text.
|
||||
* \param [out] Out Converted UTF-8 is stored here on success.
|
||||
* \returns true on success
|
||||
*/
|
||||
bool convertUTF32ToUTF8String(std::span<const UTF32> Src, std::string &Out);
|
||||
|
||||
/**
|
||||
* Converts a UTF-8 string into a UTF-16 string with native endianness.
|
||||
*
|
||||
|
||||
@@ -95,9 +95,7 @@ public:
|
||||
return makeConstIterator(getBucketsEnd(), getBucketsEnd(), *this, true);
|
||||
}
|
||||
|
||||
LLVM_NODISCARD bool empty() const {
|
||||
return getNumEntries() == 0;
|
||||
}
|
||||
[[nodiscard]] bool empty() const { return getNumEntries() == 0; }
|
||||
unsigned size() const { return getNumEntries(); }
|
||||
|
||||
/// Grow the densemap so that it can contain at least \p NumEntries items
|
||||
@@ -137,6 +135,7 @@ public:
|
||||
}
|
||||
}
|
||||
assert(NumEntries == 0 && "Node count imbalance!");
|
||||
(void)NumEntries;
|
||||
}
|
||||
setNumEntries(0);
|
||||
setNumTombstones(0);
|
||||
@@ -906,6 +905,8 @@ class SmallDenseMap
|
||||
|
||||
public:
|
||||
explicit SmallDenseMap(unsigned NumInitBuckets = 0) {
|
||||
if (NumInitBuckets > InlineBuckets)
|
||||
NumInitBuckets = NextPowerOf2(NumInitBuckets - 1);
|
||||
init(NumInitBuckets);
|
||||
}
|
||||
|
||||
@@ -1196,8 +1197,7 @@ class DenseMapIterator : DebugEpochBase::HandleBase {
|
||||
|
||||
public:
|
||||
using difference_type = ptrdiff_t;
|
||||
using value_type =
|
||||
typename std::conditional<IsConst, const Bucket, Bucket>::type;
|
||||
using value_type = std::conditional_t<IsConst, const Bucket, Bucket>;
|
||||
using pointer = value_type *;
|
||||
using reference = value_type &;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
@@ -18,7 +18,9 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
@@ -252,7 +254,7 @@ template <typename... Ts> struct DenseMapInfo<std::tuple<Ts...>> {
|
||||
|
||||
template <unsigned I>
|
||||
static unsigned getHashValueImpl(const Tuple &values, std::false_type) {
|
||||
using EltType = typename std::tuple_element<I, Tuple>::type;
|
||||
using EltType = std::tuple_element_t<I, Tuple>;
|
||||
std::integral_constant<bool, I + 1 == sizeof...(Ts)> atEnd;
|
||||
return detail::combineHashValue(
|
||||
DenseMapInfo<EltType>::getHashValue(std::get<I>(values)),
|
||||
@@ -271,7 +273,7 @@ template <typename... Ts> struct DenseMapInfo<std::tuple<Ts...>> {
|
||||
|
||||
template <unsigned I>
|
||||
static bool isEqualImpl(const Tuple &lhs, const Tuple &rhs, std::false_type) {
|
||||
using EltType = typename std::tuple_element<I, Tuple>::type;
|
||||
using EltType = std::tuple_element_t<I, Tuple>;
|
||||
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);
|
||||
@@ -288,6 +290,37 @@ template <typename... Ts> struct DenseMapInfo<std::tuple<Ts...>> {
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for variants whose all alternatives have DenseMapInfo.
|
||||
template <typename... Ts> struct DenseMapInfo<std::variant<Ts...>> {
|
||||
using Variant = std::variant<Ts...>;
|
||||
using FirstT = std::variant_alternative_t<0, Variant>;
|
||||
|
||||
static inline Variant getEmptyKey() {
|
||||
return Variant(std::in_place_index<0>, DenseMapInfo<FirstT>::getEmptyKey());
|
||||
}
|
||||
|
||||
static inline Variant getTombstoneKey() {
|
||||
return Variant(std::in_place_index<0>,
|
||||
DenseMapInfo<FirstT>::getTombstoneKey());
|
||||
}
|
||||
|
||||
static unsigned getHashValue(const Variant &Val) {
|
||||
return std::visit(
|
||||
[&Val](auto &&Alternative) {
|
||||
using T = std::decay_t<decltype(Alternative)>;
|
||||
// Include index in hash to make sure same value as different
|
||||
// alternatives don't collide.
|
||||
return detail::combineHashValue(
|
||||
DenseMapInfo<size_t>::getHashValue(Val.index()),
|
||||
DenseMapInfo<T>::getHashValue(Alternative));
|
||||
},
|
||||
Val);
|
||||
}
|
||||
|
||||
static bool isEqual(const Variant &LHS, const Variant &RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_DENSEMAPINFO_H
|
||||
|
||||
@@ -33,10 +33,10 @@ namespace wpi {
|
||||
/// is still valid.
|
||||
///
|
||||
class DebugEpochBase {
|
||||
uint64_t Epoch;
|
||||
uint64_t Epoch = 0;
|
||||
|
||||
public:
|
||||
DebugEpochBase() : Epoch(0) {}
|
||||
DebugEpochBase() = default;
|
||||
|
||||
/// Calling incrementEpoch invalidates all handles pointing into the
|
||||
/// calling instance.
|
||||
@@ -55,11 +55,11 @@ public:
|
||||
/// make an iterator-invalidating modification.
|
||||
///
|
||||
class HandleBase {
|
||||
const uint64_t *EpochAddress;
|
||||
uint64_t EpochAtCreation;
|
||||
const uint64_t *EpochAddress = nullptr;
|
||||
uint64_t EpochAtCreation = UINT64_MAX;
|
||||
|
||||
public:
|
||||
HandleBase() : EpochAddress(nullptr), EpochAtCreation(UINT64_MAX) {}
|
||||
HandleBase() = default;
|
||||
|
||||
explicit HandleBase(const DebugEpochBase *Parent)
|
||||
: EpochAddress(&Parent->Epoch), EpochAtCreation(Parent->Epoch) {}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
|
||||
#include <cerrno>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace wpi {
|
||||
namespace sys {
|
||||
|
||||
@@ -123,19 +123,34 @@ wpi_unreachable_internal(const char *msg = nullptr, const char *file = nullptr,
|
||||
|
||||
/// 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 and aborts the program.
|
||||
/// In NDEBUG builds, if the platform does not support a builtin unreachable
|
||||
/// then we call an internal LLVM runtime function. Otherwise the behavior is
|
||||
/// controlled by the CMake flag
|
||||
/// -DLLVM_UNREACHABLE_OPTIMIZE
|
||||
/// * When "ON" (default) wpi_unreachable() becomes an optimizer hint
|
||||
/// that the current location is not supposed to be reachable: the hint
|
||||
/// turns such code path into undefined behavior. On compilers that don't
|
||||
/// support such hints, prints a reduced message instead and aborts the
|
||||
/// program.
|
||||
/// * When "OFF", a builtin_trap is emitted instead of an
|
||||
// optimizer hint or printing a reduced message.
|
||||
///
|
||||
/// Use this instead of assert(0). It conveys intent more clearly and
|
||||
/// allows compilers to omit some unnecessary code.
|
||||
/// Use this instead of assert(0). It conveys intent more clearly, suppresses
|
||||
/// diagnostics for unreachable code paths, and allows compilers to omit
|
||||
/// unnecessary code.
|
||||
#ifndef NDEBUG
|
||||
#define wpi_unreachable(msg) \
|
||||
::wpi::wpi_unreachable_internal(msg, __FILE__, __LINE__)
|
||||
#elif defined(LLVM_BUILTIN_UNREACHABLE)
|
||||
#elif !defined(LLVM_BUILTIN_UNREACHABLE)
|
||||
#define wpi_unreachable(msg) ::wpi::wpi_unreachable_internal()
|
||||
#elif LLVM_UNREACHABLE_OPTIMIZE
|
||||
#define wpi_unreachable(msg) LLVM_BUILTIN_UNREACHABLE
|
||||
#else
|
||||
#define wpi_unreachable(msg) ::wpi::wpi_unreachable_internal()
|
||||
#define wpi_unreachable(msg) \
|
||||
do { \
|
||||
LLVM_BUILTIN_TRAP; \
|
||||
LLVM_BUILTIN_UNREACHABLE; \
|
||||
} while (false)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -72,7 +72,7 @@ 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<wpi::disjunction<
|
||||
using EnableIfCallable = std::enable_if_t<std::disjunction<
|
||||
std::is_void<Ret>,
|
||||
std::is_same<decltype(std::declval<CallableT>()(std::declval<Params>()...)),
|
||||
Ret>,
|
||||
@@ -106,11 +106,11 @@ protected:
|
||||
template <typename T> struct AdjustedParamTBase {
|
||||
static_assert(!std::is_reference<T>::value,
|
||||
"references should be handled by template specialization");
|
||||
using type = typename std::conditional<
|
||||
using type = std::conditional_t<
|
||||
wpi::is_trivially_copy_constructible<T>::value &&
|
||||
wpi::is_trivially_move_constructible<T>::value &&
|
||||
IsSizeLessThanThresholdT<T>::value,
|
||||
T, T &>::type;
|
||||
T, T &>;
|
||||
};
|
||||
|
||||
// This specialization ensures that 'AdjustedParam<V<T>&>' or
|
||||
@@ -167,9 +167,8 @@ protected:
|
||||
// provide four pointers worth of storage here.
|
||||
// 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;
|
||||
mutable std::aligned_storage_t<InlineStorageSize, alignof(void *)>
|
||||
InlineStorage;
|
||||
} StorageUnion;
|
||||
|
||||
// A compressed pointer to either our dispatching callback or our table of
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
@@ -126,6 +127,8 @@ hash_code hash_value(const std::tuple<Ts...> &arg);
|
||||
template <typename T>
|
||||
hash_code hash_value(const std::basic_string<T> &arg);
|
||||
|
||||
/// Compute a hash_code for a standard string.
|
||||
template <typename T> hash_code hash_value(const std::optional<T> &arg);
|
||||
|
||||
/// Override the execution seed with a fixed value.
|
||||
///
|
||||
@@ -655,24 +658,8 @@ 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...>());
|
||||
template <typename... Ts> hash_code hash_value(const std::tuple<Ts...> &arg) {
|
||||
return std::apply([](const auto &...xs) { return hash_combine(xs...); }, arg);
|
||||
}
|
||||
|
||||
// Declared and documented above, but defined here so that any of the hashing
|
||||
@@ -682,6 +669,10 @@ 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::optional<T> &arg) {
|
||||
return arg ? hash_combine(true, *arg) : hash_value(false);
|
||||
}
|
||||
|
||||
template <> struct DenseMapInfo<hash_code, void> {
|
||||
static inline hash_code getEmptyKey() { return hash_code(-1); }
|
||||
static inline hash_code getTombstoneKey() { return hash_code(-2); }
|
||||
|
||||
@@ -39,7 +39,7 @@ class MapVector {
|
||||
VectorType Vector;
|
||||
|
||||
static_assert(
|
||||
std::is_integral<typename MapType::mapped_type>::value,
|
||||
std::is_integral_v<typename MapType::mapped_type>,
|
||||
"The mapped_type of the specified Map must be an integral type");
|
||||
|
||||
public:
|
||||
@@ -109,7 +109,7 @@ public:
|
||||
|
||||
// Returns a copy of the value. Only allowed if ValueT is copyable.
|
||||
ValueT lookup(const KeyT &Key) const {
|
||||
static_assert(std::is_copy_constructible<ValueT>::value,
|
||||
static_assert(std::is_copy_constructible_v<ValueT>,
|
||||
"Cannot call lookup() if ValueT is not copyable.");
|
||||
typename MapType::const_iterator Pos = Map.find(Key);
|
||||
return Pos == Map.end()? ValueT() : Vector[Pos->second].second;
|
||||
|
||||
@@ -13,31 +13,16 @@
|
||||
#ifndef WPIUTIL_WPI_MATHEXTRAS_H
|
||||
#define WPIUTIL_WPI_MATHEXTRAS_H
|
||||
|
||||
#include "wpi/bit.h"
|
||||
#include "wpi/Compiler.h"
|
||||
#include <bit>
|
||||
#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.
|
||||
// #include <intrin.h>
|
||||
extern "C" {
|
||||
unsigned char _BitScanForward(unsigned long *_Index, unsigned long _Mask);
|
||||
unsigned char _BitScanForward64(unsigned long *_Index, unsigned __int64 _Mask);
|
||||
unsigned char _BitScanReverse(unsigned long *_Index, unsigned long _Mask);
|
||||
unsigned char _BitScanReverse64(unsigned long *_Index, unsigned __int64 _Mask);
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// The behavior an operation has on an input of 0.
|
||||
@@ -45,152 +30,31 @@ enum ZeroBehavior {
|
||||
/// The returned value is undefined.
|
||||
ZB_Undefined,
|
||||
/// The returned value is numeric_limits<T>::max()
|
||||
ZB_Max,
|
||||
/// The returned value is numeric_limits<T>::digits
|
||||
ZB_Width
|
||||
ZB_Max
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
template <typename T, std::size_t SizeOfT> struct TrailingZerosCounter {
|
||||
static unsigned count(T Val, ZeroBehavior) {
|
||||
if (!Val)
|
||||
return std::numeric_limits<T>::digits;
|
||||
if (Val & 0x1)
|
||||
return 0;
|
||||
|
||||
// Bisection method.
|
||||
unsigned ZeroBits = 0;
|
||||
T Shift = std::numeric_limits<T>::digits >> 1;
|
||||
T Mask = (std::numeric_limits<T>::max)() >> Shift;
|
||||
while (Shift) {
|
||||
if ((Val & Mask) == 0) {
|
||||
Val >>= Shift;
|
||||
ZeroBits |= Shift;
|
||||
}
|
||||
Shift >>= 1;
|
||||
Mask >>= Shift;
|
||||
}
|
||||
return ZeroBits;
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(__GNUC__) || defined(_MSC_VER)
|
||||
template <typename T> struct TrailingZerosCounter<T, 4> {
|
||||
static unsigned count(T Val, ZeroBehavior ZB) {
|
||||
if (ZB != ZB_Undefined && Val == 0)
|
||||
return 32;
|
||||
|
||||
#if __has_builtin(__builtin_ctz) || defined(__GNUC__)
|
||||
return __builtin_ctz(Val);
|
||||
#elif defined(_MSC_VER)
|
||||
unsigned long Index;
|
||||
_BitScanForward(&Index, Val);
|
||||
return Index;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#if !defined(_MSC_VER) || defined(_M_X64)
|
||||
template <typename T> struct TrailingZerosCounter<T, 8> {
|
||||
static unsigned count(T Val, ZeroBehavior ZB) {
|
||||
if (ZB != ZB_Undefined && Val == 0)
|
||||
return 64;
|
||||
|
||||
#if __has_builtin(__builtin_ctzll) || defined(__GNUC__)
|
||||
return __builtin_ctzll(Val);
|
||||
#elif defined(_MSC_VER)
|
||||
unsigned long Index;
|
||||
_BitScanForward64(&Index, Val);
|
||||
return Index;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
} // namespace detail
|
||||
|
||||
/// Count number of 0's from the least significant bit to the most
|
||||
/// stopping at the first 1.
|
||||
///
|
||||
/// Only unsigned integral types are allowed.
|
||||
///
|
||||
/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are
|
||||
/// valid arguments.
|
||||
template <typename T>
|
||||
unsigned countTrailingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
|
||||
static_assert(std::numeric_limits<T>::is_integer &&
|
||||
!std::numeric_limits<T>::is_signed,
|
||||
/// Returns std::numeric_limits<T>::digits on an input of 0.
|
||||
template <typename T> unsigned countTrailingZeros(T Val) {
|
||||
static_assert(std::is_unsigned_v<T>,
|
||||
"Only unsigned integral types are allowed.");
|
||||
return wpi::detail::TrailingZerosCounter<T, sizeof(T)>::count(Val, ZB);
|
||||
return std::countr_zero(Val);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template <typename T, std::size_t SizeOfT> struct LeadingZerosCounter {
|
||||
static unsigned count(T Val, ZeroBehavior) {
|
||||
if (!Val)
|
||||
return std::numeric_limits<T>::digits;
|
||||
|
||||
// Bisection method.
|
||||
unsigned ZeroBits = 0;
|
||||
for (T Shift = std::numeric_limits<T>::digits >> 1; Shift; Shift >>= 1) {
|
||||
T Tmp = Val >> Shift;
|
||||
if (Tmp)
|
||||
Val = Tmp;
|
||||
else
|
||||
ZeroBits |= Shift;
|
||||
}
|
||||
return ZeroBits;
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(__GNUC__) || defined(_MSC_VER)
|
||||
template <typename T> struct LeadingZerosCounter<T, 4> {
|
||||
static unsigned count(T Val, ZeroBehavior ZB) {
|
||||
if (ZB != ZB_Undefined && Val == 0)
|
||||
return 32;
|
||||
|
||||
#if __has_builtin(__builtin_clz) || defined(__GNUC__)
|
||||
return __builtin_clz(Val);
|
||||
#elif defined(_MSC_VER)
|
||||
unsigned long Index;
|
||||
_BitScanReverse(&Index, Val);
|
||||
return Index ^ 31;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#if !defined(_MSC_VER) || defined(_M_X64)
|
||||
template <typename T> struct LeadingZerosCounter<T, 8> {
|
||||
static unsigned count(T Val, ZeroBehavior ZB) {
|
||||
if (ZB != ZB_Undefined && Val == 0)
|
||||
return 64;
|
||||
|
||||
#if __has_builtin(__builtin_clzll) || defined(__GNUC__)
|
||||
return __builtin_clzll(Val);
|
||||
#elif defined(_MSC_VER)
|
||||
unsigned long Index;
|
||||
_BitScanReverse64(&Index, Val);
|
||||
return Index ^ 63;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
} // namespace detail
|
||||
|
||||
/// Count number of 0's from the most significant bit to the least
|
||||
/// stopping at the first 1.
|
||||
///
|
||||
/// Only unsigned integral types are allowed.
|
||||
///
|
||||
/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are
|
||||
/// valid arguments.
|
||||
template <typename T>
|
||||
unsigned countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
|
||||
static_assert(std::numeric_limits<T>::is_integer &&
|
||||
!std::numeric_limits<T>::is_signed,
|
||||
/// Returns std::numeric_limits<T>::digits on an input of 0.
|
||||
template <typename T> unsigned countLeadingZeros(T Val) {
|
||||
static_assert(std::is_unsigned_v<T>,
|
||||
"Only unsigned integral types are allowed.");
|
||||
return wpi::detail::LeadingZerosCounter<T, sizeof(T)>::count(Val, ZB);
|
||||
return std::countl_zero(Val);
|
||||
}
|
||||
|
||||
/// Get the index of the first set bit starting from the least
|
||||
@@ -198,13 +62,12 @@ unsigned countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
|
||||
///
|
||||
/// Only unsigned integral types are allowed.
|
||||
///
|
||||
/// \param ZB the behavior on an input of 0. Only ZB_Max and ZB_Undefined are
|
||||
/// valid arguments.
|
||||
/// \param ZB the behavior on an input of 0.
|
||||
template <typename T> T findFirstSet(T Val, ZeroBehavior ZB = ZB_Max) {
|
||||
if (ZB == ZB_Max && Val == 0)
|
||||
return (std::numeric_limits<T>::max)();
|
||||
|
||||
return countTrailingZeros(Val, ZB_Undefined);
|
||||
return std::countr_zero(Val);
|
||||
}
|
||||
|
||||
/// Create a bitmask with the N right-most bits set to 1, and all other
|
||||
@@ -239,16 +102,14 @@ template <typename T> T maskLeadingZeros(unsigned N) {
|
||||
///
|
||||
/// Only unsigned integral types are allowed.
|
||||
///
|
||||
/// \param ZB the behavior on an input of 0. Only ZB_Max and ZB_Undefined are
|
||||
/// valid arguments.
|
||||
/// \param ZB the behavior on an input of 0.
|
||||
template <typename T> T findLastSet(T Val, ZeroBehavior ZB = ZB_Max) {
|
||||
if (ZB == ZB_Max && Val == 0)
|
||||
return (std::numeric_limits<T>::max)();
|
||||
|
||||
// Use ^ instead of - because both gcc and llvm can remove the associated ^
|
||||
// in the __builtin_clz intrinsic on x86.
|
||||
return countLeadingZeros(Val, ZB_Undefined) ^
|
||||
(std::numeric_limits<T>::digits - 1);
|
||||
return std::countl_zero(Val) ^ (std::numeric_limits<T>::digits - 1);
|
||||
}
|
||||
|
||||
/// Macro compressed bit reversal table for 256 bits.
|
||||
@@ -265,8 +126,24 @@ static const unsigned char BitReverseTable256[256] = {
|
||||
};
|
||||
|
||||
/// Reverse the bits in \p Val.
|
||||
template <typename T>
|
||||
T reverseBits(T Val) {
|
||||
template <typename T> T reverseBits(T Val) {
|
||||
#if __has_builtin(__builtin_bitreverse8)
|
||||
if constexpr (std::is_same_v<T, uint8_t>)
|
||||
return __builtin_bitreverse8(Val);
|
||||
#endif
|
||||
#if __has_builtin(__builtin_bitreverse16)
|
||||
if constexpr (std::is_same_v<T, uint16_t>)
|
||||
return __builtin_bitreverse16(Val);
|
||||
#endif
|
||||
#if __has_builtin(__builtin_bitreverse32)
|
||||
if constexpr (std::is_same_v<T, uint32_t>)
|
||||
return __builtin_bitreverse32(Val);
|
||||
#endif
|
||||
#if __has_builtin(__builtin_bitreverse64)
|
||||
if constexpr (std::is_same_v<T, uint64_t>)
|
||||
return __builtin_bitreverse64(Val);
|
||||
#endif
|
||||
|
||||
unsigned char in[sizeof(Val)];
|
||||
unsigned char out[sizeof(Val)];
|
||||
std::memcpy(in, &Val, sizeof(Val));
|
||||
@@ -276,34 +153,6 @@ 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,17 +174,16 @@ constexpr inline uint64_t Make_64(uint32_t High, uint32_t Low) {
|
||||
|
||||
/// Checks if an integer fits into the given bit width.
|
||||
template <unsigned N> constexpr inline bool isInt(int64_t x) {
|
||||
return N >= 64 || (-(INT64_C(1)<<(N-1)) <= x && x < (INT64_C(1)<<(N-1)));
|
||||
}
|
||||
// Template specializations to get better code for common cases.
|
||||
template <> constexpr inline bool isInt<8>(int64_t x) {
|
||||
return static_cast<int8_t>(x) == x;
|
||||
}
|
||||
template <> constexpr inline bool isInt<16>(int64_t x) {
|
||||
return static_cast<int16_t>(x) == x;
|
||||
}
|
||||
template <> constexpr inline bool isInt<32>(int64_t x) {
|
||||
return static_cast<int32_t>(x) == x;
|
||||
if constexpr (N == 8)
|
||||
return static_cast<int8_t>(x) == x;
|
||||
if constexpr (N == 16)
|
||||
return static_cast<int16_t>(x) == x;
|
||||
if constexpr (N == 32)
|
||||
return static_cast<int32_t>(x) == x;
|
||||
if constexpr (N < 64)
|
||||
return -(INT64_C(1) << (N - 1)) <= x && x < (INT64_C(1) << (N - 1));
|
||||
(void)x; // MSVC v19.25 warns that x is unused.
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Checks if a signed integer is an N bit number shifted left by S.
|
||||
@@ -348,34 +196,20 @@ constexpr inline bool isShiftedInt(int64_t x) {
|
||||
}
|
||||
|
||||
/// Checks if an unsigned integer fits into the given bit width.
|
||||
///
|
||||
/// This is written as two functions rather than as simply
|
||||
///
|
||||
/// return N >= 64 || X < (UINT64_C(1) << N);
|
||||
///
|
||||
/// to keep MSVC from (incorrectly) warning on isUInt<64> that we're shifting
|
||||
/// left too many places.
|
||||
template <unsigned N>
|
||||
constexpr inline std::enable_if_t<(N < 64), bool> isUInt(uint64_t X) {
|
||||
template <unsigned N> constexpr inline 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 std::enable_if_t<N >= 64, bool> isUInt(uint64_t) {
|
||||
if constexpr (N == 8)
|
||||
return static_cast<uint8_t>(x) == x;
|
||||
if constexpr (N == 16)
|
||||
return static_cast<uint16_t>(x) == x;
|
||||
if constexpr (N == 32)
|
||||
return static_cast<uint32_t>(x) == x;
|
||||
if constexpr (N < 64)
|
||||
return x < (UINT64_C(1) << (N));
|
||||
(void)x; // MSVC v19.25 warns that x is unused.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Template specializations to get better code for common cases.
|
||||
template <> constexpr inline bool isUInt<8>(uint64_t x) {
|
||||
return static_cast<uint8_t>(x) == x;
|
||||
}
|
||||
template <> constexpr inline bool isUInt<16>(uint64_t x) {
|
||||
return static_cast<uint16_t>(x) == x;
|
||||
}
|
||||
template <> constexpr inline bool isUInt<32>(uint64_t x) {
|
||||
return static_cast<uint32_t>(x) == x;
|
||||
}
|
||||
|
||||
/// Checks if a unsigned integer is an N bit number shifted left by S.
|
||||
template <unsigned N, unsigned S>
|
||||
constexpr inline bool isShiftedUInt(uint64_t x) {
|
||||
@@ -462,12 +296,12 @@ constexpr inline bool isShiftedMask_64(uint64_t Value) {
|
||||
/// Return true if the argument is a power of two > 0.
|
||||
/// Ex. isPowerOf2_32(0x00100000U) == true (32 bit edition.)
|
||||
constexpr inline bool isPowerOf2_32(uint32_t Value) {
|
||||
return Value && !(Value & (Value - 1));
|
||||
return std::has_single_bit(Value);
|
||||
}
|
||||
|
||||
/// Return true if the argument is a power of two > 0 (64 bit edition.)
|
||||
constexpr inline bool isPowerOf2_64(uint64_t Value) {
|
||||
return Value && !(Value & (Value - 1));
|
||||
return std::has_single_bit(Value);
|
||||
}
|
||||
|
||||
/// Count the number of ones from the most significant bit to the first
|
||||
@@ -476,14 +310,11 @@ constexpr inline bool isPowerOf2_64(uint64_t Value) {
|
||||
/// Ex. countLeadingOnes(0xFF0FFF00) == 8.
|
||||
/// Only unsigned integral types are allowed.
|
||||
///
|
||||
/// \param ZB the behavior on an input of all ones. Only ZB_Width and
|
||||
/// ZB_Undefined are valid arguments.
|
||||
template <typename T>
|
||||
unsigned countLeadingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
|
||||
static_assert(std::numeric_limits<T>::is_integer &&
|
||||
!std::numeric_limits<T>::is_signed,
|
||||
/// Returns std::numeric_limits<T>::digits on an input of all ones.
|
||||
template <typename T> unsigned countLeadingOnes(T Value) {
|
||||
static_assert(std::is_unsigned_v<T>,
|
||||
"Only unsigned integral types are allowed.");
|
||||
return countLeadingZeros<T>(~Value, ZB);
|
||||
return std::countl_one<T>(Value);
|
||||
}
|
||||
|
||||
/// Count the number of ones from the least significant bit to the first
|
||||
@@ -492,56 +323,48 @@ unsigned countLeadingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
|
||||
/// Ex. countTrailingOnes(0x00FF00FF) == 8.
|
||||
/// Only unsigned integral types are allowed.
|
||||
///
|
||||
/// \param ZB the behavior on an input of all ones. Only ZB_Width and
|
||||
/// ZB_Undefined are valid arguments.
|
||||
template <typename T>
|
||||
unsigned countTrailingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
|
||||
static_assert(std::numeric_limits<T>::is_integer &&
|
||||
!std::numeric_limits<T>::is_signed,
|
||||
/// Returns std::numeric_limits<T>::digits on an input of all ones.
|
||||
template <typename T> unsigned countTrailingOnes(T Value) {
|
||||
static_assert(std::is_unsigned_v<T>,
|
||||
"Only unsigned integral types are allowed.");
|
||||
return countTrailingZeros<T>(~Value, ZB);
|
||||
return std::countr_one<T>(Value);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template <typename T, std::size_t SizeOfT> struct PopulationCounter {
|
||||
static unsigned count(T Value) {
|
||||
// Generic version, forward to 32 bits.
|
||||
static_assert(SizeOfT <= 4, "Not implemented!");
|
||||
#if defined(__GNUC__)
|
||||
return __builtin_popcount(Value);
|
||||
#else
|
||||
uint32_t v = Value;
|
||||
v = v - ((v >> 1) & 0x55555555);
|
||||
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
|
||||
return ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> struct PopulationCounter<T, 8> {
|
||||
static unsigned count(T Value) {
|
||||
#if defined(__GNUC__)
|
||||
return __builtin_popcountll(Value);
|
||||
#else
|
||||
uint64_t v = Value;
|
||||
v = v - ((v >> 1) & 0x5555555555555555ULL);
|
||||
v = (v & 0x3333333333333333ULL) + ((v >> 2) & 0x3333333333333333ULL);
|
||||
v = (v + (v >> 4)) & 0x0F0F0F0F0F0F0F0FULL;
|
||||
return unsigned((uint64_t)(v * 0x0101010101010101ULL) >> 56);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
/// Count the number of set bits in a value.
|
||||
/// Ex. countPopulation(0xF000F000) = 8
|
||||
/// Returns 0 if the word is zero.
|
||||
template <typename T>
|
||||
inline unsigned countPopulation(T Value) {
|
||||
static_assert(std::numeric_limits<T>::is_integer &&
|
||||
!std::numeric_limits<T>::is_signed,
|
||||
static_assert(std::is_unsigned_v<T>,
|
||||
"Only unsigned integral types are allowed.");
|
||||
return detail::PopulationCounter<T, sizeof(T)>::count(Value);
|
||||
return (unsigned)std::popcount(Value);
|
||||
}
|
||||
|
||||
/// Return true if the argument contains a non-empty sequence of ones with the
|
||||
/// remainder zero (32 bit version.) Ex. isShiftedMask_32(0x0000FF00U) == true.
|
||||
/// If true, \p MaskIdx will specify the index of the lowest set bit and \p
|
||||
/// MaskLen is updated to specify the length of the mask, else neither are
|
||||
/// updated.
|
||||
inline bool isShiftedMask_32(uint32_t Value, unsigned &MaskIdx,
|
||||
unsigned &MaskLen) {
|
||||
if (!isShiftedMask_32(Value))
|
||||
return false;
|
||||
MaskIdx = std::countr_zero(Value);
|
||||
MaskLen = std::popcount(Value);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Return true if the argument contains a non-empty sequence of ones with the
|
||||
/// remainder zero (64 bit version.) If true, \p MaskIdx will specify the index
|
||||
/// of the lowest set bit and \p MaskLen is updated to specify the length of the
|
||||
/// mask, else neither are updated.
|
||||
inline bool isShiftedMask_64(uint64_t Value, unsigned &MaskIdx,
|
||||
unsigned &MaskLen) {
|
||||
if (!isShiftedMask_64(Value))
|
||||
return false;
|
||||
MaskIdx = std::countr_zero(Value);
|
||||
MaskLen = std::popcount(Value);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Compile time Log2.
|
||||
@@ -554,90 +377,58 @@ template <size_t kValue> constexpr inline size_t CTLog2() {
|
||||
|
||||
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
|
||||
return __builtin_log(Value) / __builtin_log(2.0);
|
||||
#else
|
||||
return std::log2(Value);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Return the floor log base 2 of the specified value, -1 if the value is zero.
|
||||
/// (32 bit edition.)
|
||||
/// Ex. Log2_32(32) == 5, Log2_32(1) == 0, Log2_32(0) == -1, Log2_32(6) == 2
|
||||
inline unsigned Log2_32(uint32_t Value) {
|
||||
return static_cast<unsigned>(31 - countLeadingZeros(Value));
|
||||
return static_cast<unsigned>(31 - std::countl_zero(Value));
|
||||
}
|
||||
|
||||
/// Return the floor log base 2 of the specified value, -1 if the value is zero.
|
||||
/// (64 bit edition.)
|
||||
inline unsigned Log2_64(uint64_t Value) {
|
||||
return static_cast<unsigned>(63 - countLeadingZeros(Value));
|
||||
return static_cast<unsigned>(63 - std::countl_zero(Value));
|
||||
}
|
||||
|
||||
/// Return the ceil log base 2 of the specified value, 32 if the value is zero.
|
||||
/// (32 bit edition).
|
||||
/// Ex. Log2_32_Ceil(32) == 5, Log2_32_Ceil(1) == 0, Log2_32_Ceil(6) == 3
|
||||
inline unsigned Log2_32_Ceil(uint32_t Value) {
|
||||
return static_cast<unsigned>(32 - countLeadingZeros(Value - 1));
|
||||
return static_cast<unsigned>(32 - std::countl_zero(Value - 1));
|
||||
}
|
||||
|
||||
/// Return the ceil log base 2 of the specified value, 64 if the value is zero.
|
||||
/// (64 bit edition.)
|
||||
inline unsigned Log2_64_Ceil(uint64_t Value) {
|
||||
return static_cast<unsigned>(64 - countLeadingZeros(Value - 1));
|
||||
}
|
||||
|
||||
/// Return the greatest common divisor of the values using Euclid's algorithm.
|
||||
template <typename T>
|
||||
inline T greatestCommonDivisor(T A, T B) {
|
||||
while (B) {
|
||||
T Tmp = B;
|
||||
B = A % B;
|
||||
A = Tmp;
|
||||
}
|
||||
return A;
|
||||
}
|
||||
|
||||
inline uint64_t GreatestCommonDivisor64(uint64_t A, uint64_t B) {
|
||||
return greatestCommonDivisor<uint64_t>(A, B);
|
||||
return static_cast<unsigned>(64 - std::countl_zero(Value - 1));
|
||||
}
|
||||
|
||||
/// This function takes a 64-bit integer and returns the bit equivalent double.
|
||||
inline double BitsToDouble(uint64_t Bits) {
|
||||
double D;
|
||||
static_assert(sizeof(uint64_t) == sizeof(double), "Unexpected type sizes");
|
||||
memcpy(&D, &Bits, sizeof(Bits));
|
||||
return D;
|
||||
return wpi::bit_cast<double>(Bits);
|
||||
}
|
||||
|
||||
/// This function takes a 32-bit integer and returns the bit equivalent float.
|
||||
inline float BitsToFloat(uint32_t Bits) {
|
||||
float F;
|
||||
static_assert(sizeof(uint32_t) == sizeof(float), "Unexpected type sizes");
|
||||
memcpy(&F, &Bits, sizeof(Bits));
|
||||
return F;
|
||||
return wpi::bit_cast<float>(Bits);
|
||||
}
|
||||
|
||||
/// This function takes a double and returns the bit equivalent 64-bit integer.
|
||||
/// Note that copying doubles around changes the bits of NaNs on some hosts,
|
||||
/// notably x86, so this routine cannot be used if these bits are needed.
|
||||
inline uint64_t DoubleToBits(double Double) {
|
||||
uint64_t Bits;
|
||||
static_assert(sizeof(uint64_t) == sizeof(double), "Unexpected type sizes");
|
||||
memcpy(&Bits, &Double, sizeof(Double));
|
||||
return Bits;
|
||||
return wpi::bit_cast<uint64_t>(Double);
|
||||
}
|
||||
|
||||
/// This function takes a float and returns the bit equivalent 32-bit integer.
|
||||
/// Note that copying floats around changes the bits of NaNs on some hosts,
|
||||
/// notably x86, so this routine cannot be used if these bits are needed.
|
||||
inline uint32_t FloatToBits(float Float) {
|
||||
uint32_t Bits;
|
||||
static_assert(sizeof(uint32_t) == sizeof(float), "Unexpected type sizes");
|
||||
memcpy(&Bits, &Float, sizeof(Float));
|
||||
return Bits;
|
||||
return wpi::bit_cast<uint32_t>(Float);
|
||||
}
|
||||
|
||||
/// A and B are either alignments or offsets. Return the minimum alignment that
|
||||
@@ -653,7 +444,7 @@ constexpr inline uint64_t MinAlign(uint64_t A, uint64_t B) {
|
||||
|
||||
/// 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) {
|
||||
constexpr inline uint64_t NextPowerOf2(uint64_t A) {
|
||||
A |= (A >> 1);
|
||||
A |= (A >> 2);
|
||||
A |= (A >> 4);
|
||||
@@ -666,8 +457,7 @@ inline uint64_t NextPowerOf2(uint64_t A) {
|
||||
/// Returns the power of two which is less than or equal to the given value.
|
||||
/// Essentially, it is a floor operation across the domain of powers of two.
|
||||
inline uint64_t PowerOf2Floor(uint64_t A) {
|
||||
if (!A) return 0;
|
||||
return 1ull << (63 - countLeadingZeros(A, ZB_Undefined));
|
||||
return std::bit_floor(A);
|
||||
}
|
||||
|
||||
/// Returns the power of two which is greater than or equal to the given value.
|
||||
@@ -681,27 +471,40 @@ inline uint64_t PowerOf2Ceil(uint64_t A) {
|
||||
/// Returns the next integer (mod 2**64) that is greater than or equal to
|
||||
/// \p Value and is a multiple of \p Align. \p Align must be non-zero.
|
||||
///
|
||||
/// If non-zero \p Skew is specified, the return value will be a minimal
|
||||
/// integer that is greater than or equal to \p Value and equal to
|
||||
/// \p Align * N + \p Skew for some integer N. If \p Skew is larger than
|
||||
/// \p Align, its value is adjusted to '\p Skew mod \p Align'.
|
||||
///
|
||||
/// Examples:
|
||||
/// \code
|
||||
/// alignTo(5, 8) = 8
|
||||
/// alignTo(17, 8) = 24
|
||||
/// alignTo(~0LL, 8) = 0
|
||||
/// alignTo(321, 255) = 510
|
||||
/// \endcode
|
||||
inline uint64_t alignTo(uint64_t Value, uint64_t Align) {
|
||||
assert(Align != 0u && "Align can't be 0.");
|
||||
return (Value + Align - 1) / Align * Align;
|
||||
}
|
||||
|
||||
inline uint64_t alignToPowerOf2(uint64_t Value, uint64_t Align) {
|
||||
assert(Align != 0 && (Align & (Align - 1)) == 0 &&
|
||||
"Align must be a power of 2");
|
||||
return (Value + Align - 1) & -Align;
|
||||
}
|
||||
|
||||
/// If non-zero \p Skew is specified, the return value will be a minimal integer
|
||||
/// that is greater than or equal to \p Size and equal to \p A * N + \p Skew for
|
||||
/// some integer N. If \p Skew is larger than \p A, its value is adjusted to '\p
|
||||
/// Skew mod \p A'. \p Align must be non-zero.
|
||||
///
|
||||
/// Examples:
|
||||
/// \code
|
||||
/// alignTo(5, 8, 7) = 7
|
||||
/// alignTo(17, 8, 1) = 17
|
||||
/// alignTo(~0LL, 8, 3) = 3
|
||||
/// alignTo(321, 255, 42) = 552
|
||||
/// \endcode
|
||||
inline uint64_t alignTo(uint64_t Value, uint64_t Align, uint64_t Skew = 0) {
|
||||
inline uint64_t alignTo(uint64_t Value, uint64_t Align, uint64_t Skew) {
|
||||
assert(Align != 0u && "Align can't be 0.");
|
||||
Skew %= Align;
|
||||
return (Value + Align - 1 - Skew) / Align * Align + Skew;
|
||||
return alignTo(Value - Skew, Align) + Skew;
|
||||
}
|
||||
|
||||
/// Returns the next integer (mod 2**64) that is greater than or equal to
|
||||
@@ -785,6 +588,18 @@ SaturatingAdd(T X, T Y, bool *ResultOverflowed = nullptr) {
|
||||
return Z;
|
||||
}
|
||||
|
||||
/// Add multiple unsigned integers of type T. Clamp the result to the
|
||||
/// maximum representable value of T on overflow.
|
||||
template <class T, class... Ts>
|
||||
std::enable_if_t<std::is_unsigned_v<T>, T> SaturatingAdd(T X, T Y, T Z,
|
||||
Ts... Args) {
|
||||
bool Overflowed = false;
|
||||
T XY = SaturatingAdd(X, Y, &Overflowed);
|
||||
if (Overflowed)
|
||||
return SaturatingAdd((std::numeric_limits<T>::max)(), T(1), Args...);
|
||||
return SaturatingAdd(XY, Z, Args...);
|
||||
}
|
||||
|
||||
/// Multiply two unsigned integers, X and Y, of type T. Clamp the result to the
|
||||
/// maximum representable value of T on overflow. ResultOverflowed indicates if
|
||||
/// the result is larger than the maximum representable value of type T.
|
||||
@@ -852,7 +667,7 @@ extern const float huge_valf;
|
||||
|
||||
|
||||
/// Add two signed integers, computing the two's complement truncated result,
|
||||
/// returning true if overflow occured.
|
||||
/// returning true if overflow occurred.
|
||||
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)
|
||||
|
||||
@@ -61,19 +61,19 @@ public:
|
||||
|
||||
IntType getInt() const { return (IntType)Info::getInt(Value); }
|
||||
|
||||
void setPointer(PointerTy PtrVal) LLVM_LVALUE_FUNCTION {
|
||||
void setPointer(PointerTy PtrVal) & {
|
||||
Value = Info::updatePointer(Value, PtrVal);
|
||||
}
|
||||
|
||||
void setInt(IntType IntVal) LLVM_LVALUE_FUNCTION {
|
||||
void setInt(IntType IntVal) & {
|
||||
Value = Info::updateInt(Value, static_cast<intptr_t>(IntVal));
|
||||
}
|
||||
|
||||
void initWithPointer(PointerTy PtrVal) LLVM_LVALUE_FUNCTION {
|
||||
void initWithPointer(PointerTy PtrVal) & {
|
||||
Value = Info::updatePointer(0, PtrVal);
|
||||
}
|
||||
|
||||
void setPointerAndInt(PointerTy PtrVal, IntType IntVal) LLVM_LVALUE_FUNCTION {
|
||||
void setPointerAndInt(PointerTy PtrVal, IntType IntVal) & {
|
||||
Value = Info::updateInt(Info::updatePointer(0, PtrVal),
|
||||
static_cast<intptr_t>(IntVal));
|
||||
}
|
||||
@@ -91,7 +91,7 @@ public:
|
||||
|
||||
void *getOpaqueValue() const { return reinterpret_cast<void *>(Value); }
|
||||
|
||||
void setFromOpaqueValue(void *Val) LLVM_LVALUE_FUNCTION {
|
||||
void setFromOpaqueValue(void *Val) & {
|
||||
Value = reinterpret_cast<intptr_t>(Val);
|
||||
}
|
||||
|
||||
@@ -128,7 +128,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename PointerT, unsigned IntBits, typename PtrTraits>
|
||||
struct PointerIntPairInfo {
|
||||
static_assert(PtrTraits::NumLowBitsAvailable <
|
||||
@@ -228,6 +227,32 @@ struct PointerLikeTypeTraits<
|
||||
PtrTraits::NumLowBitsAvailable - IntBits;
|
||||
};
|
||||
|
||||
// Allow structured bindings on PointerIntPair.
|
||||
template <std::size_t I, typename PointerTy, unsigned IntBits, typename IntType,
|
||||
typename PtrTraits, typename Info>
|
||||
decltype(auto)
|
||||
get(const PointerIntPair<PointerTy, IntBits, IntType, PtrTraits, Info> &Pair) {
|
||||
static_assert(I < 2);
|
||||
if constexpr (I == 0)
|
||||
return Pair.getPointer();
|
||||
else
|
||||
return Pair.getInt();
|
||||
}
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
namespace std {
|
||||
template <typename PointerTy, unsigned IntBits, typename IntType,
|
||||
typename PtrTraits, typename Info>
|
||||
struct tuple_size<
|
||||
wpi::PointerIntPair<PointerTy, IntBits, IntType, PtrTraits, Info>>
|
||||
: std::integral_constant<std::size_t, 2> {};
|
||||
|
||||
template <std::size_t I, typename PointerTy, unsigned IntBits, typename IntType,
|
||||
typename PtrTraits, typename Info>
|
||||
struct tuple_element<
|
||||
I, wpi::PointerIntPair<PointerTy, IntBits, IntType, PtrTraits, Info>>
|
||||
: std::conditional<I == 0, PointerTy, IntType> {};
|
||||
} // namespace std
|
||||
|
||||
#endif // WPIUTIL_WPI_POINTERINTPAIR_H
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include "wpi/DenseMapInfo.h"
|
||||
#include "wpi/PointerIntPair.h"
|
||||
#include "wpi/Casting.h"
|
||||
#include "wpi/PointerLikeTypeTraits.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
@@ -132,6 +133,9 @@ namespace pointer_union_detail {
|
||||
};
|
||||
}
|
||||
|
||||
// This is a forward declaration of CastInfoPointerUnionImpl
|
||||
// Refer to its definition below for further details
|
||||
template <typename... PTs> struct CastInfoPointerUnionImpl;
|
||||
/// A discriminated union of two or more pointer types, with the discriminator
|
||||
/// in the low bit of the pointer.
|
||||
///
|
||||
@@ -167,6 +171,11 @@ class PointerUnion
|
||||
using First = TypeAtIndex<0, PTs...>;
|
||||
using Base = typename PointerUnion::PointerUnionMembers;
|
||||
|
||||
/// This is needed to give the CastInfo implementation below access
|
||||
/// to protected members.
|
||||
/// Refer to its definition for further details.
|
||||
friend struct CastInfoPointerUnionImpl<PTs...>;
|
||||
|
||||
public:
|
||||
PointerUnion() = default;
|
||||
|
||||
@@ -179,25 +188,24 @@ public:
|
||||
|
||||
explicit operator bool() const { return !isNull(); }
|
||||
|
||||
// FIXME: Replace the uses of is(), get() and dyn_cast() with
|
||||
// isa<T>, cast<T> and the wpi::dyn_cast<T>
|
||||
|
||||
/// Test if the Union currently holds the type matching T.
|
||||
template <typename T> bool is() const {
|
||||
return this->Val.getInt() == FirstIndexOfType<T, PTs...>::value;
|
||||
}
|
||||
template <typename T> inline bool is() const { return isa<T>(*this); }
|
||||
|
||||
/// 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");
|
||||
return PointerLikeTypeTraits<T>::getFromVoidPointer(this->Val.getPointer());
|
||||
template <typename T> inline T get() const {
|
||||
assert(isa<T>(*this) && "Invalid accessor called");
|
||||
return cast<T>(*this);
|
||||
}
|
||||
|
||||
/// Returns the current pointer if it is of the specified pointer type,
|
||||
/// otherwise returns null.
|
||||
template <typename T> T dyn_cast() const {
|
||||
if (is<T>())
|
||||
return get<T>();
|
||||
return T();
|
||||
template <typename T> inline T dyn_cast() const {
|
||||
return wpi::dyn_cast_if_present<T>(*this);
|
||||
}
|
||||
|
||||
/// If the union is set to the first pointer type get an address pointing to
|
||||
@@ -250,6 +258,52 @@ bool operator<(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) {
|
||||
return lhs.getOpaqueValue() < rhs.getOpaqueValue();
|
||||
}
|
||||
|
||||
/// We can't (at least, at this moment with C++14) declare CastInfo
|
||||
/// as a friend of PointerUnion like this:
|
||||
/// ```
|
||||
/// template<typename To>
|
||||
/// friend struct CastInfo<To, PointerUnion<PTs...>>;
|
||||
/// ```
|
||||
/// The compiler complains 'Partial specialization cannot be declared as a
|
||||
/// friend'.
|
||||
/// So we define this struct to be a bridge between CastInfo and
|
||||
/// PointerUnion.
|
||||
template <typename... PTs> struct CastInfoPointerUnionImpl {
|
||||
using From = PointerUnion<PTs...>;
|
||||
|
||||
template <typename To> static inline bool isPossible(From &F) {
|
||||
return F.Val.getInt() == FirstIndexOfType<To, PTs...>::value;
|
||||
}
|
||||
|
||||
template <typename To> static To doCast(From &F) {
|
||||
assert(isPossible<To>(F) && "cast to an incompatible type !");
|
||||
return PointerLikeTypeTraits<To>::getFromVoidPointer(F.Val.getPointer());
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization of CastInfo for PointerUnion
|
||||
template <typename To, typename... PTs>
|
||||
struct CastInfo<To, PointerUnion<PTs...>>
|
||||
: public DefaultDoCastIfPossible<To, PointerUnion<PTs...>,
|
||||
CastInfo<To, PointerUnion<PTs...>>> {
|
||||
using From = PointerUnion<PTs...>;
|
||||
using Impl = CastInfoPointerUnionImpl<PTs...>;
|
||||
|
||||
static inline bool isPossible(From &f) {
|
||||
return Impl::template isPossible<To>(f);
|
||||
}
|
||||
|
||||
static To doCast(From &f) { return Impl::template doCast<To>(f); }
|
||||
|
||||
static inline To castFailed() { return To(); }
|
||||
};
|
||||
|
||||
template <typename To, typename... PTs>
|
||||
struct CastInfo<To, const PointerUnion<PTs...>>
|
||||
: public ConstStrippingForwardingCast<To, const PointerUnion<PTs...>,
|
||||
CastInfo<To, PointerUnion<PTs...>>> {
|
||||
};
|
||||
|
||||
// Teach SmallPtrSet that PointerUnion is "basically a pointer", that has
|
||||
// # low bits available = min(PT1bits,PT2bits)-1.
|
||||
template <typename ...PTs>
|
||||
|
||||
@@ -17,53 +17,11 @@
|
||||
#ifndef WPIUTIL_WPI_STLFORWARDCOMPAT_H
|
||||
#define WPIUTIL_WPI_STLFORWARDCOMPAT_H
|
||||
|
||||
#include <optional>
|
||||
#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
|
||||
//===----------------------------------------------------------------------===//
|
||||
@@ -78,6 +36,30 @@ template <typename T>
|
||||
using remove_cvref_t // NOLINT(readability-identifier-naming)
|
||||
= typename wpi::remove_cvref<T>::type;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Features from C++23
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// TODO: Remove this in favor of std::optional<T>::transform once we switch to
|
||||
// C++23.
|
||||
template <typename T, typename Function>
|
||||
auto transformOptional(const std::optional<T> &O, const Function &F)
|
||||
-> std::optional<decltype(F(*O))> {
|
||||
if (O)
|
||||
return F(*O);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// TODO: Remove this in favor of std::optional<T>::transform once we switch to
|
||||
// C++23.
|
||||
template <typename T, typename Function>
|
||||
auto transformOptional(std::optional<T> &&O, const Function &F)
|
||||
-> std::optional<decltype(F(*std::move(O)))> {
|
||||
if (O)
|
||||
return F(*std::move(O));
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_STLFORWARDCOMPAT_H
|
||||
|
||||
@@ -89,7 +89,7 @@ public:
|
||||
|
||||
SmallPtrSetImplBase &operator=(const SmallPtrSetImplBase &) = delete;
|
||||
|
||||
LLVM_NODISCARD bool empty() const { return size() == 0; }
|
||||
[[nodiscard]] bool empty() const { return size() == 0; }
|
||||
size_type size() const { return NumNonEmpty - NumTombstones; }
|
||||
|
||||
void clear() {
|
||||
|
||||
@@ -140,6 +140,7 @@ class SmallSet {
|
||||
std::set<T, C> Set;
|
||||
|
||||
using VIterator = typename SmallVector<T, N>::const_iterator;
|
||||
using SIterator = typename std::set<T, C>::const_iterator;
|
||||
using mutable_iterator = typename SmallVector<T, N>::iterator;
|
||||
|
||||
// In small mode SmallPtrSet uses linear search for the elements, so it is
|
||||
@@ -153,9 +154,7 @@ public:
|
||||
|
||||
SmallSet() = default;
|
||||
|
||||
LLVM_NODISCARD bool empty() const {
|
||||
return Vector.empty() && Set.empty();
|
||||
}
|
||||
[[nodiscard]] bool empty() const { return Vector.empty() && Set.empty(); }
|
||||
|
||||
size_type size() const {
|
||||
return isSmall() ? Vector.size() : Set.size();
|
||||
@@ -172,22 +171,21 @@ public:
|
||||
}
|
||||
|
||||
/// insert - Insert an element into the set if it isn't already there.
|
||||
/// Returns true if the element is inserted (it was not in the set before).
|
||||
/// The first value of the returned pair is unused and provided for
|
||||
/// partial compatibility with the standard library self-associative container
|
||||
/// concept.
|
||||
// FIXME: Add iterators that abstract over the small and large form, and then
|
||||
// return those here.
|
||||
std::pair<std::nullopt_t, bool> insert(const T &V) {
|
||||
if (!isSmall())
|
||||
return std::make_pair(std::nullopt, Set.insert(V).second);
|
||||
/// Returns a pair. The first value of it is an iterator to the inserted
|
||||
/// element or the existing element in the set. The second value is true
|
||||
/// if the element is inserted (it was not in the set before).
|
||||
std::pair<const_iterator, bool> insert(const T &V) {
|
||||
if (!isSmall()) {
|
||||
auto [I, Inserted] = Set.insert(V);
|
||||
return std::make_pair(const_iterator(I), Inserted);
|
||||
}
|
||||
|
||||
VIterator I = vfind(V);
|
||||
if (I != Vector.end()) // Don't reinsert if it already exists.
|
||||
return std::make_pair(std::nullopt, false);
|
||||
return std::make_pair(const_iterator(I), false);
|
||||
if (Vector.size() < N) {
|
||||
Vector.push_back(V);
|
||||
return std::make_pair(std::nullopt, true);
|
||||
return std::make_pair(const_iterator(std::prev(Vector.end())), true);
|
||||
}
|
||||
|
||||
// Otherwise, grow from vector to set.
|
||||
@@ -195,8 +193,7 @@ public:
|
||||
Set.insert(Vector.back());
|
||||
Vector.pop_back();
|
||||
}
|
||||
Set.insert(V);
|
||||
return std::make_pair(std::nullopt, true);
|
||||
return std::make_pair(const_iterator(Set.insert(V).first), true);
|
||||
}
|
||||
|
||||
template <typename IterT>
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <span>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
@@ -42,6 +43,11 @@ namespace wpi {
|
||||
|
||||
template <typename IteratorT> class iterator_range;
|
||||
|
||||
template <class Iterator>
|
||||
using EnableIfConvertibleToInputIterator = std::enable_if_t<std::is_convertible<
|
||||
typename std::iterator_traits<Iterator>::iterator_category,
|
||||
std::input_iterator_tag>::value>;
|
||||
|
||||
/// This is all the stuff common to all SmallVectors.
|
||||
///
|
||||
/// The template parameter specifies the type which should be used to hold the
|
||||
@@ -67,18 +73,32 @@ protected:
|
||||
/// This is a helper for \a grow() that's out of line to reduce code
|
||||
/// duplication. This function will report a fatal error if it can't grow at
|
||||
/// least to \p MinSize.
|
||||
void *mallocForGrow(size_t MinSize, size_t TSize, size_t &NewCapacity);
|
||||
void *mallocForGrow(void *FirstEl, size_t MinSize, size_t TSize,
|
||||
size_t &NewCapacity);
|
||||
|
||||
/// This is an implementation of the grow() method which only works
|
||||
/// on POD-like data types and is out of line to reduce code duplication.
|
||||
/// This function will report a fatal error if it cannot increase capacity.
|
||||
void grow_pod(void *FirstEl, size_t MinSize, size_t TSize);
|
||||
|
||||
/// If vector was first created with capacity 0, getFirstEl() points to the
|
||||
/// memory right after, an area unallocated. If a subsequent allocation,
|
||||
/// that grows the vector, happens to return the same pointer as getFirstEl(),
|
||||
/// get a new allocation, otherwise isSmall() will falsely return that no
|
||||
/// allocation was done (true) and the memory will not be freed in the
|
||||
/// destructor. If a VSize is given (vector size), also copy that many
|
||||
/// elements to the new allocation - used if realloca fails to increase
|
||||
/// space, and happens to allocate precisely at BeginX.
|
||||
/// This is unlikely to be called often, but resolves a memory leak when the
|
||||
/// situation does occur.
|
||||
void *replaceAllocation(void *NewElts, size_t TSize, size_t NewCapacity,
|
||||
size_t VSize = 0);
|
||||
|
||||
public:
|
||||
size_t size() const { return Size; }
|
||||
size_t capacity() const { return Capacity; }
|
||||
|
||||
LLVM_NODISCARD bool empty() const { return !Size; }
|
||||
[[nodiscard]] bool empty() const { return !Size; }
|
||||
|
||||
protected:
|
||||
/// Set the array size to \p N, which the current array must have enough
|
||||
@@ -99,13 +119,14 @@ template <class T, typename = void> struct SmallVectorAlignmentAndSize {
|
||||
};
|
||||
|
||||
/// This is the part of SmallVectorTemplateBase which does not depend on whether
|
||||
/// the type T is a POD. The extra dummy template argument is used by ArrayRef
|
||||
/// the type T is a POD. The extra dummy template argument is used by std::span
|
||||
/// to avoid unnecessarily requiring T to be complete.
|
||||
template <typename T, typename = void>
|
||||
class SmallVectorTemplateCommon
|
||||
: public SmallVectorBase {
|
||||
using Base = SmallVectorBase;
|
||||
|
||||
protected:
|
||||
/// Find the address of the first element. For this pointer math to be valid
|
||||
/// with small-size of 0 for T with lots of alignment, it's important that
|
||||
/// SmallVectorStorage is properly-aligned even for small-size of 0.
|
||||
@@ -116,7 +137,6 @@ class SmallVectorTemplateCommon
|
||||
}
|
||||
// Space after 'FirstEl' is clobbered, do not add any instance vars after it.
|
||||
|
||||
protected:
|
||||
SmallVectorTemplateCommon(size_t Size) : Base(getFirstEl(), Size) {}
|
||||
|
||||
void grow_pod(size_t MinSize, size_t TSize) {
|
||||
@@ -331,8 +351,7 @@ protected:
|
||||
/// constructing elements as needed.
|
||||
template<typename It1, typename It2>
|
||||
static void uninitialized_move(It1 I, It1 E, It2 Dest) {
|
||||
std::uninitialized_copy(std::make_move_iterator(I),
|
||||
std::make_move_iterator(E), Dest);
|
||||
std::uninitialized_move(I, E, Dest);
|
||||
}
|
||||
|
||||
/// Copy the range [I, E) onto the uninitialized memory starting with "Dest",
|
||||
@@ -349,11 +368,7 @@ protected:
|
||||
|
||||
/// Create a new allocation big enough for \p MinSize and pass back its size
|
||||
/// in \p NewCapacity. This is the first section of \a grow().
|
||||
T *mallocForGrow(size_t MinSize, size_t &NewCapacity) {
|
||||
return static_cast<T *>(
|
||||
SmallVectorBase::mallocForGrow(
|
||||
MinSize, sizeof(T), NewCapacity));
|
||||
}
|
||||
T *mallocForGrow(size_t MinSize, size_t &NewCapacity);
|
||||
|
||||
/// Move existing elements over to the new allocation \p NewElts, the middle
|
||||
/// section of \a grow().
|
||||
@@ -427,6 +442,14 @@ void SmallVectorTemplateBase<T, TriviallyCopyable>::grow(size_t MinSize) {
|
||||
takeAllocationForGrow(NewElts, NewCapacity);
|
||||
}
|
||||
|
||||
template <typename T, bool TriviallyCopyable>
|
||||
T *SmallVectorTemplateBase<T, TriviallyCopyable>::mallocForGrow(
|
||||
size_t MinSize, size_t &NewCapacity) {
|
||||
return static_cast<T *>(
|
||||
SmallVectorBase::mallocForGrow(
|
||||
this->getFirstEl(), MinSize, sizeof(T), NewCapacity));
|
||||
}
|
||||
|
||||
// Define this out-of-line to dissuade the C++ compiler from inlining it.
|
||||
template <typename T, bool TriviallyCopyable>
|
||||
void SmallVectorTemplateBase<T, TriviallyCopyable>::moveElementsForGrow(
|
||||
@@ -465,8 +488,7 @@ protected:
|
||||
|
||||
/// Either const T& or T, depending on whether it's cheap enough to take
|
||||
/// parameters by value.
|
||||
using ValueParamT =
|
||||
typename std::conditional<TakesParamByValue, T, const T &>::type;
|
||||
using ValueParamT = std::conditional_t<TakesParamByValue, T, const T &>;
|
||||
|
||||
SmallVectorTemplateBase(size_t Size) : SmallVectorTemplateCommon<T>(Size) {}
|
||||
|
||||
@@ -494,8 +516,8 @@ protected:
|
||||
template <typename T1, typename T2>
|
||||
static void uninitialized_copy(
|
||||
T1 *I, T1 *E, T2 *Dest,
|
||||
std::enable_if_t<std::is_same<typename std::remove_const<T1>::type,
|
||||
T2>::value> * = nullptr) {
|
||||
std::enable_if_t<std::is_same<std::remove_const_t<T1>, T2>::value> * =
|
||||
nullptr) {
|
||||
// Use memcpy for PODs iterated by pointers (which includes SmallVector
|
||||
// iterators): std::uninitialized_copy optimizes to memmove, but we can
|
||||
// use memcpy here. Note that I and E are iterators and thus might be
|
||||
@@ -654,7 +676,7 @@ public:
|
||||
truncate(this->size() - NumItems);
|
||||
}
|
||||
|
||||
LLVM_NODISCARD T pop_back_val() {
|
||||
[[nodiscard]] T pop_back_val() {
|
||||
T Result = ::std::move(this->back());
|
||||
this->pop_back();
|
||||
return Result;
|
||||
@@ -663,11 +685,8 @@ public:
|
||||
void swap(SmallVectorImpl &RHS);
|
||||
|
||||
/// Add the specified range to the end of the SmallVector.
|
||||
template <typename in_iter,
|
||||
typename = std::enable_if_t<std::is_convertible<
|
||||
typename std::iterator_traits<in_iter>::iterator_category,
|
||||
std::input_iterator_tag>::value>>
|
||||
void append(in_iter in_start, in_iter in_end) {
|
||||
template <typename ItTy, typename = EnableIfConvertibleToInputIterator<ItTy>>
|
||||
void append(ItTy in_start, ItTy in_end) {
|
||||
this->assertSafeToAddRange(in_start, in_end);
|
||||
size_type NumInputs = std::distance(in_start, in_end);
|
||||
this->reserve(this->size() + NumInputs);
|
||||
@@ -707,11 +726,8 @@ public:
|
||||
// FIXME: Consider assigning over existing elements, rather than clearing &
|
||||
// re-initializing them - for all assign(...) variants.
|
||||
|
||||
template <typename in_iter,
|
||||
typename = std::enable_if_t<std::is_convertible<
|
||||
typename std::iterator_traits<in_iter>::iterator_category,
|
||||
std::input_iterator_tag>::value>>
|
||||
void assign(in_iter in_start, in_iter in_end) {
|
||||
template <typename ItTy, typename = EnableIfConvertibleToInputIterator<ItTy>>
|
||||
void assign(ItTy in_start, ItTy in_end) {
|
||||
this->assertSafeToReferenceAfterClear(in_start, in_end);
|
||||
clear();
|
||||
append(in_start, in_end);
|
||||
@@ -861,10 +877,7 @@ public:
|
||||
return I;
|
||||
}
|
||||
|
||||
template <typename ItTy,
|
||||
typename = std::enable_if_t<std::is_convertible<
|
||||
typename std::iterator_traits<ItTy>::iterator_category,
|
||||
std::input_iterator_tag>::value>>
|
||||
template <typename ItTy, typename = EnableIfConvertibleToInputIterator<ItTy>>
|
||||
iterator insert(iterator I, ItTy From, ItTy To) {
|
||||
// Convert iterator to elt# to avoid invalidating iterator when we reserve()
|
||||
size_t InsertElt = I - this->begin();
|
||||
@@ -952,6 +965,9 @@ public:
|
||||
return std::lexicographical_compare(this->begin(), this->end(),
|
||||
RHS.begin(), RHS.end());
|
||||
}
|
||||
bool operator>(const SmallVectorImpl &RHS) const { return RHS < *this; }
|
||||
bool operator<=(const SmallVectorImpl &RHS) const { return !(*this > RHS); }
|
||||
bool operator>=(const SmallVectorImpl &RHS) const { return !(*this < RHS); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@@ -1197,10 +1213,7 @@ public:
|
||||
this->assign(Size, Value);
|
||||
}
|
||||
|
||||
template <typename ItTy,
|
||||
typename = std::enable_if_t<std::is_convertible<
|
||||
typename std::iterator_traits<ItTy>::iterator_category,
|
||||
std::input_iterator_tag>::value>>
|
||||
template <typename ItTy, typename = EnableIfConvertibleToInputIterator<ItTy>>
|
||||
SmallVector(ItTy S, ItTy E) : SmallVectorImpl<T>(N) {
|
||||
this->append(S, E);
|
||||
}
|
||||
@@ -1212,7 +1225,13 @@ public:
|
||||
}
|
||||
|
||||
SmallVector(std::initializer_list<T> IL) : SmallVectorImpl<T>(N) {
|
||||
this->assign(IL);
|
||||
this->append(IL);
|
||||
}
|
||||
|
||||
template <typename U,
|
||||
typename = std::enable_if_t<std::is_convertible<U, T>::value>>
|
||||
explicit SmallVector(std::span<const U> A) : SmallVectorImpl<T>(N) {
|
||||
this->append(A.begin(), A.end());
|
||||
}
|
||||
|
||||
SmallVector(const SmallVector &RHS) : SmallVectorImpl<T>(N) {
|
||||
@@ -1271,8 +1290,8 @@ inline size_t capacity_in_bytes(const SmallVector<T, N> &X) {
|
||||
|
||||
template <typename RangeType>
|
||||
using ValueTypeFromRangeType =
|
||||
typename std::remove_const<typename std::remove_reference<
|
||||
decltype(*std::begin(std::declval<RangeType &>()))>::type>::type;
|
||||
std::remove_const_t<std::remove_reference_t<decltype(*std::begin(
|
||||
std::declval<RangeType &>()))>>;
|
||||
|
||||
/// Given a range of type R, iterate the entire range and return a
|
||||
/// SmallVector with elements of the vector. This is useful, for example,
|
||||
@@ -1282,10 +1301,16 @@ SmallVector<ValueTypeFromRangeType<R>, Size> to_vector(R &&Range) {
|
||||
return {std::begin(Range), std::end(Range)};
|
||||
}
|
||||
template <typename R>
|
||||
SmallVector<ValueTypeFromRangeType<R>,
|
||||
CalculateSmallVectorDefaultInlinedElements<
|
||||
ValueTypeFromRangeType<R>>::value>
|
||||
to_vector(R &&Range) {
|
||||
SmallVector<ValueTypeFromRangeType<R>> to_vector(R &&Range) {
|
||||
return {std::begin(Range), std::end(Range)};
|
||||
}
|
||||
|
||||
template <typename Out, unsigned Size, typename R>
|
||||
SmallVector<Out, Size> to_vector_of(R &&Range) {
|
||||
return {std::begin(Range), std::end(Range)};
|
||||
}
|
||||
|
||||
template <typename Out, typename R> SmallVector<Out> to_vector_of(R &&Range) {
|
||||
return {std::begin(Range), std::end(Range)};
|
||||
}
|
||||
|
||||
|
||||
@@ -111,8 +111,9 @@ public:
|
||||
/// funky memory allocation and hashing things to make it extremely efficient,
|
||||
/// storing the string data *after* the value in the map.
|
||||
template <typename ValueTy, typename AllocatorTy = MallocAllocator>
|
||||
class StringMap : public StringMapImpl {
|
||||
AllocatorTy Allocator;
|
||||
class StringMap : public StringMapImpl,
|
||||
private detail::AllocatorHolder<AllocatorTy> {
|
||||
using AllocTy = detail::AllocatorHolder<AllocatorTy>;
|
||||
|
||||
public:
|
||||
using MapEntryTy = StringMapEntry<ValueTy>;
|
||||
@@ -123,12 +124,11 @@ public:
|
||||
: StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))) {}
|
||||
|
||||
explicit StringMap(AllocatorTy A)
|
||||
: StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))), Allocator(A) {
|
||||
}
|
||||
: StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))), AllocTy(A) {}
|
||||
|
||||
StringMap(unsigned InitialSize, AllocatorTy A)
|
||||
: StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))),
|
||||
Allocator(A) {}
|
||||
AllocTy(A) {}
|
||||
|
||||
StringMap(std::initializer_list<std::pair<std::string_view, ValueTy>> List)
|
||||
: StringMapImpl(List.size(), static_cast<unsigned>(sizeof(MapEntryTy))) {
|
||||
@@ -136,11 +136,11 @@ public:
|
||||
}
|
||||
|
||||
StringMap(StringMap &&RHS)
|
||||
: StringMapImpl(std::move(RHS)), Allocator(std::move(RHS.Allocator)) {}
|
||||
: StringMapImpl(std::move(RHS)), AllocTy(std::move(RHS.getAllocator())) {}
|
||||
|
||||
StringMap(const StringMap &RHS)
|
||||
: StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))),
|
||||
Allocator(RHS.Allocator) {
|
||||
AllocTy(RHS.getAllocator()) {
|
||||
if (RHS.empty())
|
||||
return;
|
||||
|
||||
@@ -159,8 +159,8 @@ public:
|
||||
continue;
|
||||
}
|
||||
|
||||
TheTable[I] = MapEntryTy::Create(
|
||||
static_cast<MapEntryTy *>(Bucket)->getKey(), Allocator,
|
||||
TheTable[I] = MapEntryTy::create(
|
||||
static_cast<MapEntryTy *>(Bucket)->getKey(), getAllocator(),
|
||||
static_cast<MapEntryTy *>(Bucket)->getValue());
|
||||
HashTable[I] = RHSHashTable[I];
|
||||
}
|
||||
@@ -175,7 +175,7 @@ public:
|
||||
|
||||
StringMap &operator=(StringMap RHS) {
|
||||
StringMapImpl::swap(RHS);
|
||||
std::swap(Allocator, RHS.Allocator);
|
||||
std::swap(getAllocator(), RHS.getAllocator());
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -187,15 +187,14 @@ public:
|
||||
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
|
||||
StringMapEntryBase *Bucket = TheTable[I];
|
||||
if (Bucket && Bucket != getTombstoneVal()) {
|
||||
static_cast<MapEntryTy *>(Bucket)->Destroy(Allocator);
|
||||
static_cast<MapEntryTy *>(Bucket)->Destroy(getAllocator());
|
||||
}
|
||||
}
|
||||
}
|
||||
free(TheTable);
|
||||
}
|
||||
|
||||
AllocatorTy &getAllocator() { return Allocator; }
|
||||
const AllocatorTy &getAllocator() const { return Allocator; }
|
||||
using AllocTy::getAllocator;
|
||||
|
||||
using key_type = const char *;
|
||||
using mapped_type = ValueTy;
|
||||
@@ -331,7 +330,7 @@ public:
|
||||
/// if and only if the insertion takes place, and the iterator component of
|
||||
/// the pair points to the element with key equivalent to the key of the pair.
|
||||
template <typename... ArgsTy>
|
||||
std::pair<iterator, bool> try_emplace(std::string_view Key, ArgsTy &&... Args) {
|
||||
std::pair<iterator, bool> try_emplace(std::string_view Key, ArgsTy &&...Args) {
|
||||
unsigned BucketNo = LookupBucketFor(Key);
|
||||
StringMapEntryBase *&Bucket = TheTable[BucketNo];
|
||||
if (Bucket && Bucket != getTombstoneVal())
|
||||
@@ -340,7 +339,8 @@ public:
|
||||
|
||||
if (Bucket == getTombstoneVal())
|
||||
--NumTombstones;
|
||||
Bucket = MapEntryTy::Create(Key, Allocator, std::forward<ArgsTy>(Args)...);
|
||||
Bucket =
|
||||
MapEntryTy::create(Key, getAllocator(), std::forward<ArgsTy>(Args)...);
|
||||
++NumItems;
|
||||
assert(NumItems + NumTombstones <= NumBuckets);
|
||||
|
||||
@@ -358,7 +358,7 @@ public:
|
||||
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
|
||||
StringMapEntryBase *&Bucket = TheTable[I];
|
||||
if (Bucket && Bucket != getTombstoneVal()) {
|
||||
static_cast<MapEntryTy *>(Bucket)->Destroy(Allocator);
|
||||
static_cast<MapEntryTy *>(Bucket)->Destroy(getAllocator());
|
||||
}
|
||||
Bucket = nullptr;
|
||||
}
|
||||
@@ -374,7 +374,7 @@ public:
|
||||
void erase(iterator I) {
|
||||
MapEntryTy &V = *I;
|
||||
remove(&V);
|
||||
V.Destroy(Allocator);
|
||||
V.Destroy(getAllocator());
|
||||
}
|
||||
|
||||
bool erase(std::string_view Key) {
|
||||
|
||||
@@ -77,7 +77,7 @@ public:
|
||||
explicit StringMapEntryStorage(size_t keyLength)
|
||||
: StringMapEntryBase(keyLength), second() {}
|
||||
template <typename... InitTy>
|
||||
StringMapEntryStorage(size_t keyLength, InitTy &&... initVals)
|
||||
StringMapEntryStorage(size_t keyLength, InitTy &&...initVals)
|
||||
: StringMapEntryBase(keyLength),
|
||||
second(std::forward<InitTy>(initVals)...) {}
|
||||
StringMapEntryStorage(StringMapEntryStorage &e) = delete;
|
||||
@@ -88,9 +88,11 @@ public:
|
||||
void setValue(const ValueTy &V) { second = V; }
|
||||
};
|
||||
|
||||
template <> class StringMapEntryStorage<std::nullopt_t> : public StringMapEntryBase {
|
||||
template <>
|
||||
class StringMapEntryStorage<std::nullopt_t> : public StringMapEntryBase {
|
||||
public:
|
||||
explicit StringMapEntryStorage(size_t keyLength, std::nullopt_t = std::nullopt)
|
||||
explicit StringMapEntryStorage(size_t keyLength,
|
||||
std::nullopt_t = std::nullopt)
|
||||
: StringMapEntryBase(keyLength) {}
|
||||
StringMapEntryStorage(StringMapEntryStorage &entry) = delete;
|
||||
|
||||
@@ -105,6 +107,8 @@ class StringMapEntry final : public StringMapEntryStorage<ValueTy> {
|
||||
public:
|
||||
using StringMapEntryStorage<ValueTy>::StringMapEntryStorage;
|
||||
|
||||
using ValueType = ValueTy;
|
||||
|
||||
std::string_view getKey() const {
|
||||
return std::string_view(getKeyData(), this->getKeyLength());
|
||||
}
|
||||
@@ -123,7 +127,7 @@ public:
|
||||
/// Create a StringMapEntry for the specified key construct the value using
|
||||
/// \p InitiVals.
|
||||
template <typename AllocatorTy, typename... InitTy>
|
||||
static StringMapEntry *Create(std::string_view key, AllocatorTy &allocator,
|
||||
static StringMapEntry *create(std::string_view key, AllocatorTy &allocator,
|
||||
InitTy &&... initVals) {
|
||||
return new (StringMapEntryBase::allocateWithKey(
|
||||
sizeof(StringMapEntry), alignof(StringMapEntry), key, allocator))
|
||||
@@ -148,6 +152,26 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// Allow structured bindings on StringMapEntry.
|
||||
template <std::size_t Index, typename ValueTy>
|
||||
decltype(auto) get(const StringMapEntry<ValueTy> &E) {
|
||||
static_assert(Index < 2);
|
||||
if constexpr (Index == 0)
|
||||
return E.first();
|
||||
else
|
||||
return E.second;
|
||||
}
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
namespace std {
|
||||
template <typename ValueTy>
|
||||
struct tuple_size<wpi::StringMapEntry<ValueTy>>
|
||||
: std::integral_constant<std::size_t, 2> {};
|
||||
|
||||
template <std::size_t I, typename ValueTy>
|
||||
struct tuple_element<I, wpi::StringMapEntry<ValueTy>>
|
||||
: std::conditional<I == 0, std::string_view, ValueTy> {};
|
||||
} // namespace std
|
||||
|
||||
#endif // WPIUTIL_WPI_STRINGMAPENTRY_H
|
||||
|
||||
@@ -14,12 +14,10 @@
|
||||
#ifndef WPIUTIL_WPI_SWAPBYTEORDER_H
|
||||
#define WPIUTIL_WPI_SWAPBYTEORDER_H
|
||||
|
||||
#include "wpi/bit.h"
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
#if defined(_MSC_VER) && !defined(_DEBUG)
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || defined(__GNU__) || defined(__HAIKU__) || \
|
||||
defined(__Fuchsia__) || defined(__EMSCRIPTEN__)
|
||||
@@ -50,45 +48,13 @@ namespace wpi {
|
||||
|
||||
/// ByteSwap_16 - This function returns a byte-swapped representation of
|
||||
/// the 16-bit argument.
|
||||
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.
|
||||
return _byteswap_ushort(value);
|
||||
#else
|
||||
uint16_t Hi = value << 8;
|
||||
uint16_t Lo = value >> 8;
|
||||
return Hi | Lo;
|
||||
#endif
|
||||
}
|
||||
inline uint16_t ByteSwap_16(uint16_t value) { return wpi::byteswap(value); }
|
||||
|
||||
/// 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);
|
||||
#else
|
||||
uint32_t Byte0 = value & 0x000000FF;
|
||||
uint32_t Byte1 = value & 0x0000FF00;
|
||||
uint32_t Byte2 = value & 0x00FF0000;
|
||||
uint32_t Byte3 = value & 0xFF000000;
|
||||
return (Byte0 << 24) | (Byte1 << 8) | (Byte2 >> 8) | (Byte3 >> 24);
|
||||
#endif
|
||||
}
|
||||
inline uint32_t ByteSwap_32(uint32_t value) { return wpi::byteswap(value); }
|
||||
|
||||
/// 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 = ByteSwap_32(uint32_t(value));
|
||||
uint32_t Lo = ByteSwap_32(uint32_t(value >> 32));
|
||||
return (Hi << 32) | Lo;
|
||||
#endif
|
||||
}
|
||||
inline uint64_t ByteSwap_64(uint64_t value) { return wpi::byteswap(value); }
|
||||
|
||||
namespace sys {
|
||||
|
||||
@@ -100,33 +66,21 @@ constexpr bool IsBigEndianHost = false;
|
||||
|
||||
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 char getSwappedBytes(unsigned char C) { return wpi::byteswap(C); }
|
||||
inline signed char getSwappedBytes( signed char C) { return wpi::byteswap(C); }
|
||||
inline char getSwappedBytes( char C) { return wpi::byteswap(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 short getSwappedBytes(unsigned short C) { return wpi::byteswap(C); }
|
||||
inline signed short getSwappedBytes( signed short C) { return wpi::byteswap(C); }
|
||||
|
||||
inline unsigned int getSwappedBytes(unsigned int C) { return ByteSwap_32(C); }
|
||||
inline signed int getSwappedBytes( signed int C) { return ByteSwap_32(C); }
|
||||
inline unsigned int getSwappedBytes(unsigned int C) { return wpi::byteswap(C); }
|
||||
inline signed int getSwappedBytes( signed int C) { return wpi::byteswap(C); }
|
||||
|
||||
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 getSwappedBytes(unsigned long C) { return wpi::byteswap(C); }
|
||||
inline signed long getSwappedBytes( signed long C) { return wpi::byteswap(C); }
|
||||
|
||||
inline unsigned long long getSwappedBytes(unsigned long long C) {
|
||||
return ByteSwap_64(C);
|
||||
}
|
||||
inline signed long long getSwappedBytes(signed long long C) {
|
||||
return ByteSwap_64(C);
|
||||
}
|
||||
inline unsigned long long getSwappedBytes(unsigned long long C) { return wpi::byteswap(C); }
|
||||
inline signed long long getSwappedBytes( signed long long C) { return wpi::byteswap(C); }
|
||||
|
||||
inline float getSwappedBytes(float C) {
|
||||
union {
|
||||
@@ -134,7 +88,7 @@ inline float getSwappedBytes(float C) {
|
||||
float f;
|
||||
} in, out;
|
||||
in.f = C;
|
||||
out.i = ByteSwap_32(in.i);
|
||||
out.i = wpi::byteswap(in.i);
|
||||
return out.f;
|
||||
}
|
||||
|
||||
@@ -144,14 +98,14 @@ inline double getSwappedBytes(double C) {
|
||||
double d;
|
||||
} in, out;
|
||||
in.d = C;
|
||||
out.i = ByteSwap_64(in.i);
|
||||
out.i = wpi::byteswap(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)));
|
||||
wpi::byteswap(static_cast<std::underlying_type_t<T>>(C)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
||||
@@ -16,11 +16,14 @@
|
||||
|
||||
#include "wpi/DenseMapInfo.h"
|
||||
#include "wpi/Hashing.h"
|
||||
#include "wpi/Endian.h"
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
namespace wpi {
|
||||
template <typename HasherT, support::endianness Endianness>
|
||||
class HashBuilderImpl;
|
||||
class raw_ostream;
|
||||
|
||||
/// Represents a version number in the form major[.minor[.subminor[.build]]].
|
||||
@@ -37,24 +40,25 @@ class VersionTuple {
|
||||
unsigned HasBuild : 1;
|
||||
|
||||
public:
|
||||
VersionTuple()
|
||||
constexpr VersionTuple()
|
||||
: Major(0), Minor(0), HasMinor(false), Subminor(0), HasSubminor(false),
|
||||
Build(0), HasBuild(false) {}
|
||||
|
||||
explicit VersionTuple(unsigned Major)
|
||||
explicit constexpr VersionTuple(unsigned Major)
|
||||
: Major(Major), Minor(0), HasMinor(false), Subminor(0),
|
||||
HasSubminor(false), Build(0), HasBuild(false) {}
|
||||
|
||||
explicit VersionTuple(unsigned Major, unsigned Minor)
|
||||
explicit constexpr VersionTuple(unsigned Major, unsigned Minor)
|
||||
: Major(Major), Minor(Minor), HasMinor(true), Subminor(0),
|
||||
HasSubminor(false), Build(0), HasBuild(false) {}
|
||||
|
||||
explicit VersionTuple(unsigned Major, unsigned Minor, unsigned Subminor)
|
||||
explicit constexpr VersionTuple(unsigned Major, unsigned Minor,
|
||||
unsigned Subminor)
|
||||
: Major(Major), Minor(Minor), HasMinor(true), Subminor(Subminor),
|
||||
HasSubminor(true), Build(0), HasBuild(false) {}
|
||||
|
||||
explicit VersionTuple(unsigned Major, unsigned Minor, unsigned Subminor,
|
||||
unsigned Build)
|
||||
explicit constexpr VersionTuple(unsigned Major, unsigned Minor,
|
||||
unsigned Subminor, unsigned Build)
|
||||
: Major(Major), Minor(Minor), HasMinor(true), Subminor(Subminor),
|
||||
HasSubminor(true), Build(Build), HasBuild(true) {}
|
||||
|
||||
@@ -95,6 +99,12 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Return a version tuple that contains a different major version but
|
||||
/// everything else is the same.
|
||||
VersionTuple withMajorReplaced(unsigned NewMajor) const {
|
||||
return VersionTuple(NewMajor, Minor, Subminor, Build);
|
||||
}
|
||||
|
||||
/// Return a version tuple that contains only components that are non-zero.
|
||||
VersionTuple normalize() const {
|
||||
VersionTuple Result = *this;
|
||||
|
||||
99
wpiutil/src/main/native/thirdparty/llvm/include/wpi/bit.h
vendored
Normal file
99
wpiutil/src/main/native/thirdparty/llvm/include/wpi/bit.h
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
//===-- llvm/ADT/bit.h - C++20 <bit> ----------------------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// This file implements the C++20 <bit> header.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_BIT_H
|
||||
#define WPIUTIL_WPI_BIT_H
|
||||
|
||||
#include "wpi/Compiler.h"
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
#if !__has_builtin(__builtin_bit_cast)
|
||||
#include <cstring>
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_DEBUG)
|
||||
#include <cstdlib> // for _byteswap_{ushort,ulong,uint64}
|
||||
#endif
|
||||
|
||||
namespace wpi {
|
||||
|
||||
// This implementation of bit_cast is different from the C++20 one in two ways:
|
||||
// - It isn't constexpr because that requires compiler support.
|
||||
// - It requires trivially-constructible To, to avoid UB in the implementation.
|
||||
template <
|
||||
typename To, typename From,
|
||||
typename = std::enable_if_t<sizeof(To) == sizeof(From)>,
|
||||
typename = std::enable_if_t<std::is_trivially_constructible<To>::value>,
|
||||
typename = std::enable_if_t<std::is_trivially_copyable<To>::value>,
|
||||
typename = std::enable_if_t<std::is_trivially_copyable<From>::value>>
|
||||
[[nodiscard]] inline To bit_cast(const From &from) noexcept {
|
||||
#if __has_builtin(__builtin_bit_cast)
|
||||
return __builtin_bit_cast(To, from);
|
||||
#else
|
||||
To to;
|
||||
std::memcpy(&to, &from, sizeof(To));
|
||||
return to;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Reverses the bytes in the given integer value V.
|
||||
template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
|
||||
[[nodiscard]] constexpr T byteswap(T V) noexcept {
|
||||
if constexpr (sizeof(T) == 1) {
|
||||
return V;
|
||||
} else if constexpr (sizeof(T) == 2) {
|
||||
uint16_t UV = V;
|
||||
#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.
|
||||
return _byteswap_ushort(UV);
|
||||
#else
|
||||
uint16_t Hi = UV << 8;
|
||||
uint16_t Lo = UV >> 8;
|
||||
return Hi | Lo;
|
||||
#endif
|
||||
} else if constexpr (sizeof(T) == 4) {
|
||||
uint32_t UV = V;
|
||||
#if __has_builtin(__builtin_bswap32)
|
||||
return __builtin_bswap32(UV);
|
||||
#elif defined(_MSC_VER) && !defined(_DEBUG)
|
||||
return _byteswap_ulong(UV);
|
||||
#else
|
||||
uint32_t Byte0 = UV & 0x000000FF;
|
||||
uint32_t Byte1 = UV & 0x0000FF00;
|
||||
uint32_t Byte2 = UV & 0x00FF0000;
|
||||
uint32_t Byte3 = UV & 0xFF000000;
|
||||
return (Byte0 << 24) | (Byte1 << 8) | (Byte2 >> 8) | (Byte3 >> 24);
|
||||
#endif
|
||||
} else if constexpr (sizeof(T) == 8) {
|
||||
uint64_t UV = V;
|
||||
#if __has_builtin(__builtin_bswap64)
|
||||
return __builtin_bswap64(UV);
|
||||
#elif defined(_MSC_VER) && !defined(_DEBUG)
|
||||
return _byteswap_uint64(UV);
|
||||
#else
|
||||
uint64_t Hi = wpi::byteswap<uint32_t>(UV);
|
||||
uint32_t Lo = wpi::byteswap<uint32_t>(UV >> 32);
|
||||
return (Hi << 32) | Lo;
|
||||
#endif
|
||||
} else {
|
||||
static_assert(!sizeof(T *), "Don't know how to handle the given type.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif
|
||||
@@ -14,15 +14,14 @@
|
||||
#define WPIUTIL_WPI_RAW_OSTREAM_H
|
||||
|
||||
#include "wpi/SmallVector.h"
|
||||
#include <span>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#if __cplusplus > 201402L
|
||||
#include <string_view>
|
||||
#endif
|
||||
#include <system_error>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
@@ -229,6 +228,20 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if defined(__cpp_char8_t)
|
||||
// When using `char8_t *` integers or pointers are written to the ostream
|
||||
// instead of UTF-8 code as one might expect. This might lead to unexpected
|
||||
// behavior, especially as `u8""` literals are of type `char8_t*` instead of
|
||||
// type `char_t*` from C++20 onwards. Thus we disallow using them with
|
||||
// raw_ostreams.
|
||||
// If you have u8"" literals to stream, you can rewrite them as ordinary
|
||||
// literals with escape sequences
|
||||
// e.g. replace `u8"\u00a0"` by `"\xc2\xa0"`
|
||||
// or use `reinterpret_cast`:
|
||||
// e.g. replace `u8"\u00a0"` by `reinterpret_cast<const char *>(u8"\u00a0")`
|
||||
raw_ostream &operator<<(const char8_t *Str) = delete;
|
||||
#endif
|
||||
|
||||
raw_ostream &operator<<(const char *Str) {
|
||||
// Inline fast path, particularly for constant strings where a sufficiently
|
||||
// smart compiler will simplify strlen.
|
||||
@@ -734,7 +747,7 @@ class buffer_ostream : public raw_svector_ostream {
|
||||
raw_ostream &OS;
|
||||
SmallVector<char, 0> Buffer;
|
||||
|
||||
virtual void anchor() override;
|
||||
void anchor() override;
|
||||
|
||||
public:
|
||||
buffer_ostream(raw_ostream &OS) : raw_svector_ostream(Buffer), OS(OS) {}
|
||||
@@ -745,7 +758,7 @@ class buffer_unique_ostream : public raw_svector_ostream {
|
||||
std::unique_ptr<raw_ostream> OS;
|
||||
SmallVector<char, 0> Buffer;
|
||||
|
||||
virtual void anchor() override;
|
||||
void anchor() override;
|
||||
|
||||
public:
|
||||
buffer_unique_ostream(std::unique_ptr<raw_ostream> OS)
|
||||
|
||||
@@ -98,7 +98,6 @@ 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