diff --git a/CHANGELOG.md b/CHANGELOG.md
index d7037b47e..b49e47641 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
# Changelog
+## Unreleased
+
+**Features**
+
+- Updated libswift demangle to v6.3.1. ([#980](https://github.com/getsentry/symbolic/pull/980))
+
## 13.0.0
**Features**
diff --git a/symbolic-demangle/build.rs b/symbolic-demangle/build.rs
index 1ec58b0a7..ef354b003 100644
--- a/symbolic-demangle/build.rs
+++ b/symbolic-demangle/build.rs
@@ -7,14 +7,11 @@ fn main() {
.files(&[
"src/swiftdemangle.cpp",
"vendor/swift/lib/Demangling/Context.cpp",
- "vendor/swift/lib/Demangling/CrashReporter.cpp",
"vendor/swift/lib/Demangling/Demangler.cpp",
"vendor/swift/lib/Demangling/Errors.cpp",
"vendor/swift/lib/Demangling/ManglingUtils.cpp",
"vendor/swift/lib/Demangling/NodeDumper.cpp",
"vendor/swift/lib/Demangling/NodePrinter.cpp",
- // "vendor/swift/lib/Demangling/OldDemangler.cpp",
- // "vendor/swift/lib/Demangling/OldRemangler.cpp",
"vendor/swift/lib/Demangling/Punycode.cpp",
"vendor/swift/lib/Demangling/Remangler.cpp",
])
diff --git a/symbolic-demangle/tests/test_swift.rs b/symbolic-demangle/tests/test_swift.rs
index d3994accc..082c43a14 100644
--- a/symbolic-demangle/tests/test_swift.rs
+++ b/symbolic-demangle/tests/test_swift.rs
@@ -297,6 +297,12 @@ fn test_demangle_swift_no_args() {
// Swift 6.0.3
"$ss27withTaskCancellationHandler9operation8onCancel9isolationxxyYaKXE_yyYbXEScA_pSgYitYaKlFTwb" => "withTaskCancellationHandler",
- "$s11Supercharge2AXO7ElementPAAE8elements33_35EDDAA799FBB5B74D2F426690B0D99DLL3for2asSayqd__GSo28NSAccessibilityAttributeNamea_qd__mtSo7AXErrorVYKAcDRd__lFAC3AppC_AC6WindowCTgm5" => "specialized AX.Element.elements",
+
+ // Swift 6.1.0
+ "$sTB" => "$sTB",
+
+ // Swift 6.3.1
+ "$s12SharedDomain7ServiceC06streamC0_4bodyACXDScSyxG_yxYaYbKYCcts8SendableRzlFZyycAA06StreamC0CYbcfu_yycfu0_Tm" => "implicit closure #2 in implicit closure #1 in static Service.streamService",
+ "$s18OrderedCollections0A10DictionaryV20uniqueKeysWithValuesACyxq_Gqd___tcSTRd__x_q_t7ElementRtd__lufC6TaggedAHVy8SportsUI0J23ParticipantRowViewModelVSSG_ALs15LazyMapSequenceVySayALGAM_ALtGTt0g5Tf4g_n" => "specialized OrderedDictionary.init",
});
}
diff --git a/symbolic-demangle/vendor/swift/1-arguments.patch b/symbolic-demangle/vendor/swift/1-arguments.patch
index 5209fc4c2..f01f37bfe 100644
--- a/symbolic-demangle/vendor/swift/1-arguments.patch
+++ b/symbolic-demangle/vendor/swift/1-arguments.patch
@@ -1,14 +1,14 @@
-commit 80e772078494a73f2fbb5e385de2092e6057d913
+commit 7dddbd0e4b5ba23e640c1a4d531dc148f6d18aca
Author: David Herberth
-Date: Thu Jan 9 10:54:28 2025 +0100
+Date: Mon May 18 14:50:49 2026 +0200
- apply patch
+ patch
diff --git a/symbolic-demangle/vendor/swift/include/swift/Demangling/Demangle.h b/symbolic-demangle/vendor/swift/include/swift/Demangling/Demangle.h
-index f66dd7fd..940c3652 100644
+index 7a1b6c4a..3df6b0b9 100644
--- a/symbolic-demangle/vendor/swift/include/swift/Demangling/Demangle.h
+++ b/symbolic-demangle/vendor/swift/include/swift/Demangling/Demangle.h
-@@ -58,6 +58,7 @@ struct DemangleOptions {
+@@ -62,6 +62,7 @@ struct DemangleOptions {
bool ShortenArchetype = false;
bool ShowPrivateDiscriminators = true;
bool ShowFunctionArgumentTypes = true;
@@ -16,7 +16,7 @@ index f66dd7fd..940c3652 100644
bool DisplayDebuggerGeneratedModule = true;
bool DisplayStdlibModule = true;
bool DisplayObjCModule = true;
-@@ -90,6 +91,7 @@ struct DemangleOptions {
+@@ -94,6 +95,7 @@ struct DemangleOptions {
Opt.ShortenArchetype = true;
Opt.ShowPrivateDiscriminators = false;
Opt.ShowFunctionArgumentTypes = false;
@@ -25,32 +25,21 @@ index f66dd7fd..940c3652 100644
return Opt;
};
diff --git a/symbolic-demangle/vendor/swift/lib/Demangling/NodePrinter.cpp b/symbolic-demangle/vendor/swift/lib/Demangling/NodePrinter.cpp
-index 6c309bbf..5b251e8d 100644
+index 66840b56..7430062a 100644
--- a/symbolic-demangle/vendor/swift/lib/Demangling/NodePrinter.cpp
+++ b/symbolic-demangle/vendor/swift/lib/Demangling/NodePrinter.cpp
-@@ -955,10 +955,11 @@ private:
- if (isSendable)
- Printer << "@Sendable ";
-
-- printFunctionParameters(LabelList, node->getChild(argIndex), depth,
-- Options.ShowFunctionArgumentTypes);
-+ if (Options.ShowFunctionArgumentTypes) {
-+ printFunctionParameters(LabelList, node->getChild(argIndex), depth, true);
-+ }
-
-- if (!Options.ShowFunctionArgumentTypes)
-+ if (!Options.ShowFunctionReturnType)
- return;
-
- if (isAsync)
-diff --git a/symbolic-demangle/vendor/swift/lib/Demangling/Demangler.cpp b/symbolic-demangle/vendor/swift/lib/Demangling/Demangler.cpp
-index 6c309bbf..5b251e8d 100644
---- a/symbolic-demangle/vendor/swift/lib/Demangling/Demangler.cpp
-+++ b/symbolic-demangle/vendor/swift/lib/Demangling/Demangler.cpp
-@@ -3423,7 +3423,6 @@ NodePointer Demangler::demangleSpecAttributes(Node::Kind SpecKind) {
+@@ -945,10 +945,11 @@ void NodePrinter::printFunctionType(NodePointer LabelList, NodePointer node,
+ if (isSendable)
+ Printer << "@Sendable ";
- int PassID = (int)nextChar() - '0';
- if (PassID < 0 || PassID >= MAX_SPECIALIZATION_PASS) {
-- assert(false && "unexpected pass id");
- return nullptr;
- }
+- printFunctionParameters(LabelList, node->getChild(argIndex), depth,
+- Options.ShowFunctionArgumentTypes);
++ if (Options.ShowFunctionArgumentTypes) {
++ printFunctionParameters(LabelList, node->getChild(argIndex), depth, true);
++ }
+
+- if (!Options.ShowFunctionArgumentTypes)
++ if (!Options.ShowFunctionReturnType)
+ return;
+
+ if (isAsync)
diff --git a/symbolic-demangle/vendor/swift/README.md b/symbolic-demangle/vendor/swift/README.md
index 4bd7fddaf..95a944809 100644
--- a/symbolic-demangle/vendor/swift/README.md
+++ b/symbolic-demangle/vendor/swift/README.md
@@ -3,7 +3,7 @@
This folder contains a vendored subset of the [Swift Programming Language]. The Swift library is
reduced to the demangler only to reduce the size of this package.
-The current version is **Swift 5.5.1**.
+The current version is **Swift 6.3.1**.
## Sentry Modifications
@@ -21,15 +21,15 @@ patch is maintained in `1-arguments.patch`.
```
$ git clone https://github.com/apple/swift.git
```
- 3. Check out dependencies:
- ```
- $ ./swift/utils/update-checkout --clone
- ```
- 4. Check out the release branch of the latest release:
+ 3. Check out the release branch of the latest release:
```
$ cd swift
$ git checkout swift-5.5.1-RELEASE
```
+ 4. Check out dependencies:
+ ```
+ $ ./utils/update-checkout --clone
+ ```
5. Build the complete swift project (be very patient, this may take long):
```
$ ./utils/build-script --skip-build
diff --git a/symbolic-demangle/vendor/swift/include/llvm/ADT/DenseMapInfo.h b/symbolic-demangle/vendor/swift/include/llvm/ADT/DenseMapInfo.h
index 07c37e353..b850223c9 100644
--- a/symbolic-demangle/vendor/swift/include/llvm/ADT/DenseMapInfo.h
+++ b/symbolic-demangle/vendor/swift/include/llvm/ADT/DenseMapInfo.h
@@ -17,6 +17,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -320,6 +321,28 @@ struct DenseMapInfo>> {
static bool isEqual(const Enum &LHS, const Enum &RHS) { return LHS == RHS; }
};
+
+template struct DenseMapInfo> {
+ using Optional = std::optional;
+ using Info = DenseMapInfo;
+
+ static inline Optional getEmptyKey() { return {Info::getEmptyKey()}; }
+
+ static inline Optional getTombstoneKey() { return {Info::getTombstoneKey()}; }
+
+ static unsigned getHashValue(const Optional &OptionalVal) {
+ return detail::combineHashValue(
+ OptionalVal.has_value(),
+ Info::getHashValue(OptionalVal.value_or(Info::getEmptyKey())));
+ }
+
+ static bool isEqual(const Optional &LHS, const Optional &RHS) {
+ if (LHS && RHS) {
+ return Info::isEqual(LHS.value(), RHS.value());
+ }
+ return !LHS && !RHS;
+ }
+};
} // end namespace llvm
#endif // LLVM_ADT_DENSEMAPINFO_H
diff --git a/symbolic-demangle/vendor/swift/include/llvm/ADT/Hashing.h b/symbolic-demangle/vendor/swift/include/llvm/ADT/Hashing.h
index a5477362a..2bebff2cb 100644
--- a/symbolic-demangle/vendor/swift/include/llvm/ADT/Hashing.h
+++ b/symbolic-demangle/vendor/swift/include/llvm/ADT/Hashing.h
@@ -44,6 +44,7 @@
#ifndef LLVM_ADT_HASHING_H
#define LLVM_ADT_HASHING_H
+#include "llvm/ADT/ADL.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/SwapByteOrder.h"
@@ -151,7 +152,7 @@ namespace detail {
inline uint64_t fetch64(const char *p) {
uint64_t result;
- memcpy(&result, p, sizeof(result));
+ std::memcpy(&result, p, sizeof(result));
if (sys::IsBigEndianHost)
sys::swapByteOrder(result);
return result;
@@ -159,7 +160,7 @@ inline uint64_t fetch64(const char *p) {
inline uint32_t fetch32(const char *p) {
uint32_t result;
- memcpy(&result, p, sizeof(result));
+ std::memcpy(&result, p, sizeof(result));
if (sys::IsBigEndianHost)
sys::swapByteOrder(result);
return result;
@@ -328,7 +329,7 @@ struct hash_state {
/// This variable can be set using the \see llvm::set_fixed_execution_seed
/// function. See that function for details. Do not, under any circumstances,
/// set or read this variable.
-extern uint64_t fixed_seed_override;
+LLVM_ABI extern uint64_t fixed_seed_override;
inline uint64_t get_execution_seed() {
// FIXME: This needs to be a per-execution seed. This is just a placeholder
@@ -401,7 +402,7 @@ bool store_and_advance(char *&buffer_ptr, char *buffer_end, const T& value,
if (buffer_ptr + store_size > buffer_end)
return false;
const char *value_data = reinterpret_cast(&value);
- memcpy(buffer_ptr, value_data + offset, store_size);
+ std::memcpy(buffer_ptr, value_data + offset, store_size);
buffer_ptr += store_size;
return true;
}
@@ -492,6 +493,10 @@ hash_code hash_combine_range(InputIteratorT first, InputIteratorT last) {
return ::llvm::hashing::detail::hash_combine_range_impl(first, last);
}
+// A wrapper for hash_combine_range above.
+template hash_code hash_combine_range(RangeT &&R) {
+ return hash_combine_range(adl_begin(R), adl_end(R));
+}
// Implementation details for hash_combine.
namespace hashing {
@@ -531,7 +536,7 @@ struct hash_combine_recursive_helper {
// with the variadic combine because that formation can have varying
// argument types.
size_t partial_store_size = buffer_end - buffer_ptr;
- memcpy(buffer_ptr, &data, partial_store_size);
+ std::memcpy(buffer_ptr, &data, partial_store_size);
// If the store fails, our buffer is full and ready to hash. We have to
// either initialize the hash state (on the first full buffer) or mix
@@ -667,7 +672,7 @@ template hash_code hash_value(const std::tuple &arg) {
// infrastructure is available.
template
hash_code hash_value(const std::basic_string &arg) {
- return hash_combine_range(arg.begin(), arg.end());
+ return hash_combine_range(arg);
}
template hash_code hash_value(const std::optional &arg) {
diff --git a/symbolic-demangle/vendor/swift/include/llvm/ADT/PointerIntPair.h b/symbolic-demangle/vendor/swift/include/llvm/ADT/PointerIntPair.h
new file mode 100644
index 000000000..9cfc65846
--- /dev/null
+++ b/symbolic-demangle/vendor/swift/include/llvm/ADT/PointerIntPair.h
@@ -0,0 +1,293 @@
+//===- llvm/ADT/PointerIntPair.h - Pair for pointer and int -----*- 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 defines the PointerIntPair class.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_POINTERINTPAIR_H
+#define LLVM_ADT_POINTERINTPAIR_H
+
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/PointerLikeTypeTraits.h"
+#include "llvm/Support/type_traits.h"
+#include
+#include
+#include
+#include
+
+namespace llvm {
+
+namespace detail {
+template struct PunnedPointer {
+ static_assert(sizeof(Ptr) == sizeof(intptr_t), "");
+
+ // Asserts that allow us to let the compiler implement the destructor and
+ // copy/move constructors
+ static_assert(std::is_trivially_destructible::value, "");
+ static_assert(std::is_trivially_copy_constructible::value, "");
+ static_assert(std::is_trivially_move_constructible::value, "");
+
+ explicit constexpr PunnedPointer(intptr_t i = 0) { *this = i; }
+
+ constexpr intptr_t asInt() const {
+ intptr_t R = 0;
+ std::memcpy(&R, Data, sizeof(R));
+ return R;
+ }
+
+ constexpr operator intptr_t() const { return asInt(); }
+
+ constexpr PunnedPointer &operator=(intptr_t V) {
+ std::memcpy(Data, &V, sizeof(Data));
+ return *this;
+ }
+
+ Ptr *getPointerAddress() { return reinterpret_cast(Data); }
+ const Ptr *getPointerAddress() const { return reinterpret_cast(Data); }
+
+private:
+ alignas(Ptr) unsigned char Data[sizeof(Ptr)];
+};
+} // namespace detail
+
+template struct DenseMapInfo;
+template
+struct PointerIntPairInfo;
+
+/// PointerIntPair - This class implements a pair of a pointer and small
+/// integer. It is designed to represent this in the space required by one
+/// pointer by bitmangling the integer into the low part of the pointer. This
+/// can only be done for small integers: typically up to 3 bits, but it depends
+/// on the number of bits available according to PointerLikeTypeTraits for the
+/// type.
+///
+/// Note that PointerIntPair always puts the IntVal part in the highest bits
+/// possible. For example, PointerIntPair will put the bit for
+/// the bool into bit #2, not bit #0, which allows the low two bits to be used
+/// for something else. For example, this allows:
+/// PointerIntPair, 1, bool>
+/// ... and the two bools will land in different bits.
+template ,
+ typename Info = PointerIntPairInfo>
+class PointerIntPair {
+ // Used by MSVC visualizer and generally helpful for debugging/visualizing.
+ using InfoTy = Info;
+ detail::PunnedPointer Value;
+
+public:
+ constexpr PointerIntPair() = default;
+
+ PointerIntPair(PointerTy PtrVal, IntType IntVal) {
+ setPointerAndInt(PtrVal, IntVal);
+ }
+
+ explicit PointerIntPair(PointerTy PtrVal) { initWithPointer(PtrVal); }
+
+ PointerTy getPointer() const { return Info::getPointer(Value); }
+
+ IntType getInt() const { return (IntType)Info::getInt(Value); }
+
+ void setPointer(PointerTy PtrVal) & {
+ Value = Info::updatePointer(Value, PtrVal);
+ }
+
+ void setInt(IntType IntVal) & {
+ Value = Info::updateInt(Value, static_cast(IntVal));
+ }
+
+ void initWithPointer(PointerTy PtrVal) & {
+ Value = Info::updatePointer(0, PtrVal);
+ }
+
+ void setPointerAndInt(PointerTy PtrVal, IntType IntVal) & {
+ Value = Info::updateInt(Info::updatePointer(0, PtrVal),
+ static_cast(IntVal));
+ }
+
+ PointerTy const *getAddrOfPointer() const {
+ return const_cast(this)->getAddrOfPointer();
+ }
+
+ PointerTy *getAddrOfPointer() {
+ assert(Value == reinterpret_cast(getPointer()) &&
+ "Can only return the address if IntBits is cleared and "
+ "PtrTraits doesn't change the pointer");
+ return Value.getPointerAddress();
+ }
+
+ void *getOpaqueValue() const {
+ return reinterpret_cast(Value.asInt());
+ }
+
+ void setFromOpaqueValue(void *Val) & {
+ Value = reinterpret_cast(Val);
+ }
+
+ static PointerIntPair getFromOpaqueValue(void *V) {
+ PointerIntPair P;
+ P.setFromOpaqueValue(V);
+ return P;
+ }
+
+ // Allow PointerIntPairs to be created from const void * if and only if the
+ // pointer type could be created from a const void *.
+ static PointerIntPair getFromOpaqueValue(const void *V) {
+ (void)PtrTraits::getFromVoidPointer(V);
+ return getFromOpaqueValue(const_cast(V));
+ }
+
+ bool operator==(const PointerIntPair &RHS) const {
+ return Value == RHS.Value;
+ }
+
+ bool operator!=(const PointerIntPair &RHS) const {
+ return Value != RHS.Value;
+ }
+
+ bool operator<(const PointerIntPair &RHS) const { return Value < RHS.Value; }
+ bool operator>(const PointerIntPair &RHS) const { return Value > RHS.Value; }
+
+ bool operator<=(const PointerIntPair &RHS) const {
+ return Value <= RHS.Value;
+ }
+
+ bool operator>=(const PointerIntPair &RHS) const {
+ return Value >= RHS.Value;
+ }
+};
+
+template
+struct PointerIntPairInfo {
+ static_assert(PtrTraits::NumLowBitsAvailable <
+ std::numeric_limits::digits,
+ "cannot use a pointer type that has all bits free");
+ static_assert(IntBits <= PtrTraits::NumLowBitsAvailable,
+ "PointerIntPair with integer size too large for pointer");
+ enum MaskAndShiftConstants : uintptr_t {
+ /// PointerBitMask - The bits that come from the pointer.
+ PointerBitMask =
+ ~(uintptr_t)(((intptr_t)1 << PtrTraits::NumLowBitsAvailable) - 1),
+
+ /// IntShift - The number of low bits that we reserve for other uses, and
+ /// keep zero.
+ IntShift = (uintptr_t)PtrTraits::NumLowBitsAvailable - IntBits,
+
+ /// IntMask - This is the unshifted mask for valid bits of the int type.
+ IntMask = (uintptr_t)(((intptr_t)1 << IntBits) - 1),
+
+ // ShiftedIntMask - This is the bits for the integer shifted in place.
+ ShiftedIntMask = (uintptr_t)(IntMask << IntShift)
+ };
+
+ static PointerT getPointer(intptr_t Value) {
+ return PtrTraits::getFromVoidPointer(
+ reinterpret_cast(Value & PointerBitMask));
+ }
+
+ static intptr_t getInt(intptr_t Value) {
+ return (Value >> IntShift) & IntMask;
+ }
+
+ static intptr_t updatePointer(intptr_t OrigValue, PointerT Ptr) {
+ intptr_t PtrWord =
+ reinterpret_cast(PtrTraits::getAsVoidPointer(Ptr));
+ assert((PtrWord & ~PointerBitMask) == 0 &&
+ "Pointer is not sufficiently aligned");
+ // Preserve all low bits, just update the pointer.
+ return PtrWord | (OrigValue & ~PointerBitMask);
+ }
+
+ static intptr_t updateInt(intptr_t OrigValue, intptr_t Int) {
+ assert((Int & ~IntMask) == 0 && "Integer too large for field");
+
+ // Preserve all bits other than the ones we are updating.
+ return (OrigValue & ~ShiftedIntMask) | Int << IntShift;
+ }
+};
+
+// Provide specialization of DenseMapInfo for PointerIntPair.
+template
+struct DenseMapInfo, void> {
+ using Ty = PointerIntPair;
+
+ static Ty getEmptyKey() {
+ uintptr_t Val = static_cast(-1);
+ Val <<= PointerLikeTypeTraits::NumLowBitsAvailable;
+ return Ty::getFromOpaqueValue(reinterpret_cast(Val));
+ }
+
+ static Ty getTombstoneKey() {
+ uintptr_t Val = static_cast(-2);
+ Val <<= PointerLikeTypeTraits::NumLowBitsAvailable;
+ return Ty::getFromOpaqueValue(reinterpret_cast(Val));
+ }
+
+ static unsigned getHashValue(Ty V) {
+ uintptr_t IV = reinterpret_cast(V.getOpaqueValue());
+ return unsigned(IV) ^ unsigned(IV >> 9);
+ }
+
+ static bool isEqual(const Ty &LHS, const Ty &RHS) { return LHS == RHS; }
+};
+
+// Teach SmallPtrSet that PointerIntPair is "basically a pointer".
+template
+struct PointerLikeTypeTraits<
+ PointerIntPair> {
+ static inline void *
+ getAsVoidPointer(const PointerIntPair &P) {
+ return P.getOpaqueValue();
+ }
+
+ static inline PointerIntPair
+ getFromVoidPointer(void *P) {
+ return PointerIntPair::getFromOpaqueValue(P);
+ }
+
+ static inline PointerIntPair
+ getFromVoidPointer(const void *P) {
+ return PointerIntPair::getFromOpaqueValue(P);
+ }
+
+ static constexpr int NumLowBitsAvailable =
+ PtrTraits::NumLowBitsAvailable - IntBits;
+};
+
+// Allow structured bindings on PointerIntPair.
+template
+decltype(auto)
+get(const PointerIntPair &Pair) {
+ static_assert(I < 2);
+ if constexpr (I == 0)
+ return Pair.getPointer();
+ else
+ return Pair.getInt();
+}
+
+} // end namespace llvm
+
+namespace std {
+template
+struct tuple_size<
+ llvm::PointerIntPair>
+ : std::integral_constant {};
+
+template
+struct tuple_element<
+ I, llvm::PointerIntPair>
+ : std::conditional {};
+} // namespace std
+
+#endif // LLVM_ADT_POINTERINTPAIR_H
diff --git a/symbolic-demangle/vendor/swift/include/llvm/ADT/STLExtras.h b/symbolic-demangle/vendor/swift/include/llvm/ADT/STLExtras.h
index 8f988d01c..45acb75cf 100644
--- a/symbolic-demangle/vendor/swift/include/llvm/ADT/STLExtras.h
+++ b/symbolic-demangle/vendor/swift/include/llvm/ADT/STLExtras.h
@@ -35,6 +35,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -320,10 +321,19 @@ template class Callable {
/// Returns true if the given container only contains a single element.
template bool hasSingleElement(ContainerTy &&C) {
- auto B = std::begin(C), E = std::end(C);
+ auto B = adl_begin(C);
+ auto E = adl_end(C);
return B != E && std::next(B) == E;
}
+/// Asserts that the given container has a single element and returns that
+/// element.
+template
+decltype(auto) getSingleElement(ContainerTy &&C) {
+ assert(hasSingleElement(C) && "expected container with single element");
+ return *adl_begin(C);
+}
+
/// Return a range covering \p RangeOrContainer with the first N elements
/// excluded.
template auto drop_begin(T &&RangeOrContainer, size_t N = 1) {
@@ -375,8 +385,7 @@ inline mapped_iterator map_iterator(ItTy I, FuncTy F) {
template
auto map_range(ContainerTy &&C, FuncTy F) {
- return make_range(map_iterator(std::begin(C), F),
- map_iterator(std::end(C), F));
+ return make_range(map_iterator(adl_begin(C), F), map_iterator(adl_end(C), F));
}
/// A base type of mapped iterator, that is useful for building derived
@@ -416,7 +425,8 @@ static constexpr bool HasFreeFunctionRBegin =
} // namespace detail
// Returns an iterator_range over the given container which iterates in reverse.
-template auto reverse(ContainerTy &&C) {
+// Does not mutate the container.
+template [[nodiscard]] auto reverse(ContainerTy &&C) {
if constexpr (detail::HasFreeFunctionRBegin)
return make_range(adl_rbegin(C), adl_rend(C));
else
@@ -572,11 +582,9 @@ iterator_range, PredicateT>>
make_filter_range(RangeT &&Range, PredicateT Pred) {
using FilterIteratorT =
filter_iterator, PredicateT>;
- return make_range(
- FilterIteratorT(std::begin(std::forward(Range)),
- std::end(std::forward(Range)), Pred),
- FilterIteratorT(std::end(std::forward(Range)),
- std::end(std::forward(Range)), Pred));
+ auto B = adl_begin(Range);
+ auto E = adl_end(Range);
+ return make_range(FilterIteratorT(B, E, Pred), FilterIteratorT(E, E, Pred));
}
/// A pseudo-iterator adaptor that is designed to implement "early increment"
@@ -656,8 +664,8 @@ iterator_range>>
make_early_inc_range(RangeT &&Range) {
using EarlyIncIteratorT =
early_inc_iterator_impl>;
- return make_range(EarlyIncIteratorT(std::begin(std::forward(Range))),
- EarlyIncIteratorT(std::end(std::forward(Range))));
+ return make_range(EarlyIncIteratorT(adl_begin(Range)),
+ EarlyIncIteratorT(adl_end(Range)));
}
// Forward declarations required by zip_shortest/zip_equal/zip_first/zip_longest
@@ -1023,6 +1031,16 @@ class concat_iterator
std::forward_iterator_tag, ValueT> {
using BaseT = typename concat_iterator::iterator_facade_base;
+ static constexpr bool ReturnsByValue =
+ !(std::is_reference_v())> && ...);
+
+ using reference_type =
+ typename std::conditional_t;
+
+ using handle_type =
+ typename std::conditional_t,
+ ValueT *>;
+
/// We store both the current and end iterators for each concatenated
/// sequence in a tuple of pairs.
///
@@ -1065,27 +1083,30 @@ class concat_iterator
/// Returns null if the specified iterator is at the end. Otherwise,
/// dereferences the iterator and returns the address of the resulting
/// reference.
- template ValueT *getHelper() const {
+ template handle_type getHelper() const {
auto &Begin = std::get(Begins);
auto &End = std::get(Ends);
if (Begin == End)
- return nullptr;
+ return {};
- return &*Begin;
+ if constexpr (ReturnsByValue)
+ return *Begin;
+ else
+ return &*Begin;
}
/// Finds the first non-end iterator, dereferences, and returns the resulting
/// reference.
///
/// It is an error to call this with all iterators at the end.
- template ValueT &get(std::index_sequence) const {
+ template reference_type get(std::index_sequence) const {
// Build a sequence of functions to get from iterator if possible.
- ValueT *(concat_iterator::*GetHelperFns[])() const = {
- &concat_iterator::getHelper...};
+ handle_type (concat_iterator::*GetHelperFns[])()
+ const = {&concat_iterator::getHelper...};
// Loop over them, and return the first result we find.
for (auto &GetHelperFn : GetHelperFns)
- if (ValueT *P = (this->*GetHelperFn)())
+ if (auto P = (this->*GetHelperFn)())
return *P;
llvm_unreachable("Attempted to get a pointer from an end concat iterator!");
@@ -1097,8 +1118,8 @@ class concat_iterator
/// We need the full range to know how to switch between each of the
/// iterators.
template
- explicit concat_iterator(RangeTs &&... Ranges)
- : Begins(std::begin(Ranges)...), Ends(std::end(Ranges)...) {}
+ explicit concat_iterator(RangeTs &&...Ranges)
+ : Begins(adl_begin(Ranges)...), Ends(adl_end(Ranges)...) {}
using BaseT::operator++;
@@ -1107,7 +1128,7 @@ class concat_iterator
return *this;
}
- ValueT &operator*() const {
+ reference_type operator*() const {
return get(std::index_sequence_for());
}
@@ -1127,13 +1148,12 @@ template class concat_range {
public:
using iterator =
concat_iterator()))...>;
+ decltype(adl_begin(std::declval()))...>;
private:
std::tuple Ranges;
- template
- iterator begin_impl(std::index_sequence) {
+ template iterator begin_impl(std::index_sequence) {
return iterator(std::get(Ranges)...);
}
template
@@ -1141,12 +1161,12 @@ template class concat_range {
return iterator(std::get(Ranges)...);
}
template iterator end_impl(std::index_sequence) {
- return iterator(make_range(std::end(std::get(Ranges)),
- std::end(std::get(Ranges)))...);
+ return iterator(make_range(adl_end(std::get(Ranges)),
+ adl_end(std::get(Ranges)))...);
}
template iterator end_impl(std::index_sequence) const {
- return iterator(make_range(std::end(std::get(Ranges)),
- std::end(std::get(Ranges)))...);
+ return iterator(make_range(adl_end(std::get(Ranges)),
+ adl_end(std::get(Ranges)))...);
}
public:
@@ -1169,11 +1189,13 @@ template class concat_range {
} // end namespace detail
-/// Concatenated range across two or more ranges.
+/// Returns a concatenated range across two or more ranges. Does not modify the
+/// ranges.
///
/// The desired value type must be explicitly specified.
template
-detail::concat_range concat(RangeTs &&... Ranges) {
+[[nodiscard]] detail::concat_range
+concat(RangeTs &&...Ranges) {
static_assert(sizeof...(RangeTs) > 1,
"Need more than one range to concatenate!");
return detail::concat_range(
@@ -1194,7 +1216,8 @@ class indexed_accessor_iterator
return index - rhs.index;
}
bool operator==(const indexed_accessor_iterator &rhs) const {
- return base == rhs.base && index == rhs.index;
+ assert(base == rhs.base && "incompatible iterators");
+ return index == rhs.index;
}
bool operator<(const indexed_accessor_iterator &rhs) const {
assert(base == rhs.base && "incompatible iterators");
@@ -1420,7 +1443,7 @@ template class first_or_second_type {
/// Given a container of pairs, return a range over the first elements.
template auto make_first_range(ContainerTy &&c) {
- using EltTy = decltype((*std::begin(c)));
+ using EltTy = decltype(*adl_begin(c));
return llvm::map_range(std::forward(c),
[](EltTy elt) -> typename detail::first_or_second_type<
EltTy, decltype((elt.first))>::type {
@@ -1430,7 +1453,7 @@ template auto make_first_range(ContainerTy &&c) {
/// Given a container of pairs, return a range over the second elements.
template auto make_second_range(ContainerTy &&c) {
- using EltTy = decltype((*std::begin(c)));
+ using EltTy = decltype(*adl_begin(c));
return llvm::map_range(
std::forward(c),
[](EltTy elt) ->
@@ -1709,6 +1732,34 @@ template constexpr size_t range_size(R &&Range) {
return static_cast(std::distance(adl_begin(Range), adl_end(Range)));
}
+/// Wrapper for std::accumulate.
+template auto accumulate(R &&Range, E &&Init) {
+ return std::accumulate(adl_begin(Range), adl_end(Range),
+ std::forward(Init));
+}
+
+/// Wrapper for std::accumulate with a binary operator.
+template
+auto accumulate(R &&Range, E &&Init, BinaryOp &&Op) {
+ return std::accumulate(adl_begin(Range), adl_end(Range),
+ std::forward(Init), std::forward(Op));
+}
+
+/// Returns the sum of all values in `Range` with `Init` initial value.
+/// The default initial value is 0.
+template >
+auto sum_of(R &&Range, E Init = E{0}) {
+ return accumulate(std::forward(Range), std::move(Init));
+}
+
+/// Returns the product of all values in `Range` with `Init` initial value.
+/// The default initial value is 1.
+template >
+auto product_of(R &&Range, E Init = E{1}) {
+ return accumulate(std::forward(Range), std::move(Init),
+ std::multiplies<>{});
+}
+
/// Provide wrappers to std::for_each which take ranges instead of having to
/// pass begin/end explicitly.
template
@@ -1737,6 +1788,12 @@ bool none_of(R &&Range, UnaryPredicate P) {
return std::none_of(adl_begin(Range), adl_end(Range), P);
}
+/// Provide wrappers to std::fill which take ranges instead of having to pass
+/// begin/end explicitly.
+template void fill(R &&Range, T &&Value) {
+ std::fill(adl_begin(Range), adl_end(Range), std::forward(Value));
+}
+
/// Provide wrappers to std::find which take ranges instead of having to pass
/// begin/end explicitly.
template auto find(R &&Range, const T &Val) {
@@ -1782,8 +1839,9 @@ T *find_singleton(R &&Range, Predicate P, bool AllowRepeats = false) {
if (RC) {
if (!AllowRepeats || PRC != RC)
return nullptr;
- } else
+ } else {
RC = PRC;
+ }
}
}
return RC;
@@ -1813,8 +1871,9 @@ std::pair find_singleton_nested(R &&Range, Predicate P,
if (RC) {
if (!AllowRepeats || PRC.first != RC)
return {nullptr, true};
- } else
+ } else {
RC = PRC.first;
+ }
}
}
return {RC, false};
@@ -1843,6 +1902,13 @@ OutputIt replace_copy(R &&Range, OutputIt Out, const T &OldValue,
NewValue);
}
+/// Provide wrappers to std::replace which take ranges instead of having to pass
+/// begin/end explicitly.
+template
+void replace(R &&Range, const T &OldValue, const T &NewValue) {
+ std::replace(adl_begin(Range), adl_end(Range), OldValue, NewValue);
+}
+
/// Provide wrappers to std::move which take ranges instead of having to
/// pass begin/end explicitly.
template
@@ -1909,6 +1975,28 @@ template bool is_sorted(R &&Range) {
return std::is_sorted(adl_begin(Range), adl_end(Range));
}
+/// Provide wrappers to std::includes which take ranges instead of having to
+/// pass begin/end explicitly.
+/// This function checks if the sorted range \p R2 is a subsequence of the
+/// sorted range \p R1. The ranges must be sorted in non-descending order.
+template bool includes(R1 &&Range1, R2 &&Range2) {
+ assert(is_sorted(Range1) && "Range1 must be sorted in non-descending order");
+ assert(is_sorted(Range2) && "Range2 must be sorted in non-descending order");
+ return std::includes(adl_begin(Range1), adl_end(Range1), adl_begin(Range2),
+ adl_end(Range2));
+}
+
+/// This function checks if the sorted range \p R2 is a subsequence of the
+/// sorted range \p R1. The ranges must be sorted with respect to a comparator
+/// \p C.
+template
+bool includes(R1 &&Range1, R2 &&Range2, Compare &&C) {
+ assert(is_sorted(Range1, C) && "Range1 must be sorted with respect to C");
+ assert(is_sorted(Range2, C) && "Range2 must be sorted with respect to C");
+ return std::includes(adl_begin(Range1), adl_end(Range1), adl_begin(Range2),
+ adl_end(Range2), std::forward(C));
+}
+
/// Wrapper function around std::count to count the number of times an element
/// \p Element occurs in the given range \p Range.
template auto count(R &&Range, const E &Element) {
@@ -1975,6 +2063,8 @@ auto upper_bound(R &&Range, T &&Value, Compare C) {
std::forward(Value), C);
}
+/// Provide wrappers to std::min_element which take ranges instead of having to
+/// pass begin/end explicitly.
template auto min_element(R &&Range) {
return std::min_element(adl_begin(Range), adl_end(Range));
}
@@ -1983,6 +2073,8 @@ template auto min_element(R &&Range, Compare C) {
return std::min_element(adl_begin(Range), adl_end(Range), C);
}
+/// Provide wrappers to std::max_element which take ranges instead of having to
+/// pass begin/end explicitly.
template auto max_element(R &&Range) {
return std::max_element(adl_begin(Range), adl_end(Range));
}
@@ -1991,6 +2083,25 @@ template auto max_element(R &&Range, Compare C) {
return std::max_element(adl_begin(Range), adl_end(Range), C);
}
+/// Provide wrappers to std::mismatch which take ranges instead of having to
+/// pass begin/end explicitly.
+/// This function returns a pair of iterators for the first mismatching elements
+/// from `R1` and `R2`. As an example, if:
+///
+/// R1 = [0, 1, 4, 6], R2 = [0, 1, 5, 6]
+///
+/// this function will return a pair of iterators, first pointing to R1[2] and
+/// second pointing to R2[2].
+template auto mismatch(R1 &&Range1, R2 &&Range2) {
+ return std::mismatch(adl_begin(Range1), adl_end(Range1), adl_begin(Range2),
+ adl_end(Range2));
+}
+
+template
+auto uninitialized_copy(R &&Src, IterTy Dst) {
+ return std::uninitialized_copy(adl_begin(Src), adl_end(Src), Dst);
+}
+
template
void stable_sort(R &&Range) {
std::stable_sort(adl_begin(Range), adl_end(Range));
@@ -2037,7 +2148,7 @@ bool equal(L &&LRange, R &&RRange, BinaryPredicate P) {
template bool all_equal(R &&Range) {
auto Begin = adl_begin(Range);
auto End = adl_end(Range);
- return Begin == End || std::equal(Begin + 1, End, Begin);
+ return Begin == End || std::equal(std::next(Begin), End, Begin);
}
/// Returns true if all Values in the initializer lists are equal or the list
@@ -2084,7 +2195,7 @@ void append_values(Container &C, Args &&...Values) {
/// Given a sequence container Cont, replace the range [ContIt, ContEnd) with
/// the range [ValIt, ValEnd) (which is not from the same container).
-template
+template
void replace(Container &Cont, typename Container::iterator ContIt,
typename Container::iterator ContEnd, RandomAccessIterator ValIt,
RandomAccessIterator ValEnd) {
@@ -2092,21 +2203,24 @@ void replace(Container &Cont, typename Container::iterator ContIt,
if (ValIt == ValEnd) {
Cont.erase(ContIt, ContEnd);
return;
- } else if (ContIt == ContEnd) {
+ }
+ if (ContIt == ContEnd) {
Cont.insert(ContIt, ValIt, ValEnd);
return;
}
- *ContIt++ = *ValIt++;
+ *ContIt = *ValIt;
+ ++ContIt;
+ ++ValIt;
}
}
/// Given a sequence container Cont, replace the range [ContIt, ContEnd) with
/// the range R.
-template>
+template >
void replace(Container &Cont, typename Container::iterator ContIt,
- typename Container::iterator ContEnd, Range R) {
- replace(Cont, ContIt, ContEnd, R.begin(), R.end());
+ typename Container::iterator ContEnd, Range &&R) {
+ replace(Cont, ContIt, ContEnd, adl_begin(R), adl_end(R));
}
/// An STL-style algorithm similar to std::for_each that applies a second
@@ -2366,7 +2480,7 @@ class index_range {
detail::index_iterator end() const { return {End}; }
};
-/// Given two or more input ranges, returns a new range whose values are are
+/// Given two or more input ranges, returns a new range whose values are
/// tuples (A, B, C, ...), such that A is the 0-based index of the item in the
/// sequence, and B, C, ..., are the values from the original input ranges. All
/// input ranges are required to have equal lengths. Note that the returned
@@ -2519,19 +2633,19 @@ bool hasNItemsOrLess(
/// Returns true if the given container has exactly N items
template bool hasNItems(ContainerTy &&C, unsigned N) {
- return hasNItems(std::begin(C), std::end(C), N);
+ return hasNItems(adl_begin(C), adl_end(C), N);
}
/// Returns true if the given container has N or more items
template
bool hasNItemsOrMore(ContainerTy &&C, unsigned N) {
- return hasNItemsOrMore(std::begin(C), std::end(C), N);
+ return hasNItemsOrMore(adl_begin(C), adl_end(C), N);
}
/// Returns true if the given container has N or less items
template
bool hasNItemsOrLess(ContainerTy &&C, unsigned N) {
- return hasNItemsOrLess(std::begin(C), std::end(C), N);
+ return hasNItemsOrLess(adl_begin(C), adl_end(C), N);
}
/// Returns a raw pointer that represents the same address as the argument.
diff --git a/symbolic-demangle/vendor/swift/include/llvm/ADT/STLForwardCompat.h b/symbolic-demangle/vendor/swift/include/llvm/ADT/STLForwardCompat.h
index 6afe3610b..7bd2c8705 100644
--- a/symbolic-demangle/vendor/swift/include/llvm/ADT/STLForwardCompat.h
+++ b/symbolic-demangle/vendor/swift/include/llvm/ADT/STLForwardCompat.h
@@ -36,6 +36,19 @@ template
using remove_cvref_t // NOLINT(readability-identifier-naming)
= typename llvm::remove_cvref::type;
+// TODO: Remove this in favor of std::type_identity once we switch to C++23.
+template
+struct type_identity // NOLINT(readability-identifier-naming)
+{
+ using type = T;
+};
+
+// TODO: Remove this in favor of std::type_identity_t once we switch to
+// C++23.
+template
+using type_identity_t // NOLINT(readability-identifier-naming)
+ = typename llvm::type_identity::type;
+
//===----------------------------------------------------------------------===//
// Features from C++23
//===----------------------------------------------------------------------===//
@@ -67,6 +80,11 @@ template
return static_cast>(E);
}
+// A tag for constructors accepting ranges.
+struct from_range_t {
+ explicit from_range_t() = default;
+};
+inline constexpr from_range_t from_range{};
} // namespace llvm
#endif // LLVM_ADT_STLFORWARDCOMPAT_H
diff --git a/symbolic-demangle/vendor/swift/include/llvm/ADT/STLFunctionalExtras.h b/symbolic-demangle/vendor/swift/include/llvm/ADT/STLFunctionalExtras.h
index dd7fc6dc7..a4d50dc36 100644
--- a/symbolic-demangle/vendor/swift/include/llvm/ADT/STLFunctionalExtras.h
+++ b/symbolic-demangle/vendor/swift/include/llvm/ADT/STLFunctionalExtras.h
@@ -16,6 +16,7 @@
#define LLVM_ADT_STLFUNCTIONALEXTRAS_H
#include "llvm/ADT/STLForwardCompat.h"
+#include "llvm/Support/Compiler.h"
#include
#include
@@ -35,8 +36,8 @@ namespace llvm {
/// a function_ref.
template class function_ref;
-template
-class function_ref {
+template
+class LLVM_GSL_POINTER function_ref {
Ret (*callback)(intptr_t callable, Params ...params) = nullptr;
intptr_t callable;
@@ -52,7 +53,7 @@ class function_ref {
template
function_ref(
- Callable &&callable,
+ Callable &&callable LLVM_LIFETIME_BOUND,
// This is not the copy-constructor.
std::enable_if_t,
function_ref>::value> * = nullptr,
@@ -69,6 +70,10 @@ class function_ref {
}
explicit operator bool() const { return callback; }
+
+ bool operator==(const function_ref &Other) const {
+ return callable == Other.callable;
+ }
};
} // end namespace llvm
diff --git a/symbolic-demangle/vendor/swift/include/llvm/ADT/StringRef.h b/symbolic-demangle/vendor/swift/include/llvm/ADT/StringRef.h
index 049f22b03..16aca4d45 100644
--- a/symbolic-demangle/vendor/swift/include/llvm/ADT/StringRef.h
+++ b/symbolic-demangle/vendor/swift/include/llvm/ADT/StringRef.h
@@ -17,6 +17,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -31,14 +32,18 @@ namespace llvm {
class StringRef;
/// Helper functions for StringRef::getAsInteger.
- bool getAsUnsignedInteger(StringRef Str, unsigned Radix,
- unsigned long long &Result);
+ LLVM_ABI bool getAsUnsignedInteger(StringRef Str, unsigned Radix,
+ unsigned long long &Result);
- bool getAsSignedInteger(StringRef Str, unsigned Radix, long long &Result);
+ LLVM_ABI bool getAsSignedInteger(StringRef Str, unsigned Radix,
+ long long &Result);
- bool consumeUnsignedInteger(StringRef &Str, unsigned Radix,
- unsigned long long &Result);
- bool consumeSignedInteger(StringRef &Str, unsigned Radix, long long &Result);
+ LLVM_ABI unsigned getAutoSenseRadix(StringRef &Str);
+
+ LLVM_ABI bool consumeUnsignedInteger(StringRef &Str, unsigned Radix,
+ unsigned long long &Result);
+ LLVM_ABI bool consumeSignedInteger(StringRef &Str, unsigned Radix,
+ long long &Result);
/// StringRef - Represent a constant reference to a string, i.e. a character
/// array and a length, which need not be null terminated.
@@ -54,6 +59,9 @@ namespace llvm {
using iterator = const char *;
using const_iterator = const char *;
using size_type = size_t;
+ using value_type = char;
+ using reverse_iterator = std::reverse_iterator;
+ using const_reverse_iterator = std::reverse_iterator;
private:
/// The start of the string, in an external buffer.
@@ -81,7 +89,7 @@ namespace llvm {
StringRef(std::nullptr_t) = delete;
/// Construct a string ref from a cstring.
- /*implicit*/ constexpr StringRef(const char *Str)
+ /*implicit*/ constexpr StringRef(const char *Str LLVM_LIFETIME_BOUND)
: Data(Str), Length(Str ?
// GCC 7 doesn't have constexpr char_traits. Fall back to __builtin_strlen.
#if defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE < 8
@@ -93,12 +101,13 @@ namespace llvm {
}
/// Construct a string ref from a pointer and length.
- /*implicit*/ constexpr StringRef(const char *data, size_t length)
+ /*implicit*/ constexpr StringRef(const char *data LLVM_LIFETIME_BOUND,
+ size_t length)
: Data(data), Length(length) {}
/// Construct a string ref from an std::string.
/*implicit*/ StringRef(const std::string &Str)
- : Data(Str.data()), Length(Str.length()) {}
+ : Data(Str.data()), Length(Str.length()) {}
/// Construct a string ref from an std::string_view.
/*implicit*/ constexpr StringRef(std::string_view Str)
@@ -108,9 +117,17 @@ namespace llvm {
/// @name Iterators
/// @{
- iterator begin() const { return Data; }
+ iterator begin() const { return data(); }
+
+ iterator end() const { return data() + size(); }
- iterator end() const { return Data + Length; }
+ reverse_iterator rbegin() const {
+ return std::make_reverse_iterator(end());
+ }
+
+ reverse_iterator rend() const {
+ return std::make_reverse_iterator(begin());
+ }
const unsigned char *bytes_begin() const {
return reinterpret_cast(begin());
@@ -131,7 +148,7 @@ namespace llvm {
[[nodiscard]] constexpr const char *data() const { return Data; }
/// empty - Check if the string is empty.
- [[nodiscard]] constexpr bool empty() const { return Length == 0; }
+ [[nodiscard]] constexpr bool empty() const { return size() == 0; }
/// size - Get the string size.
[[nodiscard]] constexpr size_t size() const { return Length; }
@@ -139,13 +156,13 @@ namespace llvm {
/// front - Get the first character in the string.
[[nodiscard]] char front() const {
assert(!empty());
- return Data[0];
+ return data()[0];
}
/// back - Get the last character in the string.
[[nodiscard]] char back() const {
assert(!empty());
- return Data[Length-1];
+ return data()[size() - 1];
}
// copy - Allocate copy in Allocator and return StringRef to it.
@@ -154,14 +171,14 @@ namespace llvm {
// Don't request a length 0 copy from the allocator.
if (empty())
return StringRef();
- char *S = A.template Allocate(Length);
+ char *S = A.template Allocate(size());
std::copy(begin(), end(), S);
- return StringRef(S, Length);
+ return StringRef(S, size());
}
/// Check for string equality, ignoring case.
[[nodiscard]] bool equals_insensitive(StringRef RHS) const {
- return Length == RHS.Length && compare_insensitive(RHS) == 0;
+ return size() == RHS.size() && compare_insensitive(RHS) == 0;
}
/// compare - Compare two strings; the result is negative, zero, or positive
@@ -169,21 +186,22 @@ namespace llvm {
/// the \p RHS.
[[nodiscard]] int compare(StringRef RHS) const {
// Check the prefix for a mismatch.
- if (int Res = compareMemory(Data, RHS.Data, std::min(Length, RHS.Length)))
+ if (int Res =
+ compareMemory(data(), RHS.data(), std::min(size(), RHS.size())))
return Res < 0 ? -1 : 1;
// Otherwise the prefixes match, so we only need to check the lengths.
- if (Length == RHS.Length)
+ if (size() == RHS.size())
return 0;
- return Length < RHS.Length ? -1 : 1;
+ return size() < RHS.size() ? -1 : 1;
}
/// Compare two strings, ignoring case.
- [[nodiscard]] int compare_insensitive(StringRef RHS) const;
+ [[nodiscard]] LLVM_ABI int compare_insensitive(StringRef RHS) const;
/// compare_numeric - Compare two strings, treating sequences of digits as
/// numbers.
- [[nodiscard]] int compare_numeric(StringRef RHS) const;
+ [[nodiscard]] LLVM_ABI int compare_numeric(StringRef RHS) const;
/// Determine the edit distance between this string and another
/// string.
@@ -203,18 +221,19 @@ namespace llvm {
/// or (if \p AllowReplacements is \c true) replacements needed to
/// transform one of the given strings into the other. If zero,
/// the strings are identical.
- [[nodiscard]] unsigned edit_distance(StringRef Other,
- bool AllowReplacements = true,
- unsigned MaxEditDistance = 0) const;
+ [[nodiscard]] LLVM_ABI unsigned
+ edit_distance(StringRef Other, bool AllowReplacements = true,
+ unsigned MaxEditDistance = 0) const;
- [[nodiscard]] unsigned
+ [[nodiscard]] LLVM_ABI unsigned
edit_distance_insensitive(StringRef Other, bool AllowReplacements = true,
unsigned MaxEditDistance = 0) const;
/// str - Get the contents as an std::string.
[[nodiscard]] std::string str() const {
- if (!Data) return std::string();
- return std::string(Data, Length);
+ if (!data())
+ return std::string();
+ return std::string(data(), size());
}
/// @}
@@ -222,8 +241,8 @@ namespace llvm {
/// @{
[[nodiscard]] char operator[](size_t Index) const {
- assert(Index < Length && "Invalid index!");
- return Data[Index];
+ assert(Index < size() && "Invalid index!");
+ return data()[Index];
}
/// Disallow accidental assignment from a temporary std::string.
@@ -248,28 +267,28 @@ namespace llvm {
/// Check if this string starts with the given \p Prefix.
[[nodiscard]] bool starts_with(StringRef Prefix) const {
- return Length >= Prefix.Length &&
- compareMemory(Data, Prefix.Data, Prefix.Length) == 0;
+ return size() >= Prefix.size() &&
+ compareMemory(data(), Prefix.data(), Prefix.size()) == 0;
}
[[nodiscard]] bool starts_with(char Prefix) const {
return !empty() && front() == Prefix;
}
/// Check if this string starts with the given \p Prefix, ignoring case.
- [[nodiscard]] bool starts_with_insensitive(StringRef Prefix) const;
+ [[nodiscard]] LLVM_ABI bool starts_with_insensitive(StringRef Prefix) const;
/// Check if this string ends with the given \p Suffix.
[[nodiscard]] bool ends_with(StringRef Suffix) const {
- return Length >= Suffix.Length &&
- compareMemory(end() - Suffix.Length, Suffix.Data, Suffix.Length) ==
- 0;
+ return size() >= Suffix.size() &&
+ compareMemory(end() - Suffix.size(), Suffix.data(),
+ Suffix.size()) == 0;
}
[[nodiscard]] bool ends_with(char Suffix) const {
return !empty() && back() == Suffix;
}
/// Check if this string ends with the given \p Suffix, ignoring case.
- [[nodiscard]] bool ends_with_insensitive(StringRef Suffix) const;
+ [[nodiscard]] LLVM_ABI bool ends_with_insensitive(StringRef Suffix) const;
/// @}
/// @name String Searching
@@ -287,7 +306,8 @@ namespace llvm {
///
/// \returns The index of the first occurrence of \p C, or npos if not
/// found.
- [[nodiscard]] size_t find_insensitive(char C, size_t From = 0) const;
+ [[nodiscard]] LLVM_ABI size_t find_insensitive(char C,
+ size_t From = 0) const;
/// Search for the first character satisfying the predicate \p F
///
@@ -317,23 +337,24 @@ namespace llvm {
///
/// \returns The index of the first occurrence of \p Str, or npos if not
/// found.
- [[nodiscard]] size_t find(StringRef Str, size_t From = 0) const;
+ [[nodiscard]] LLVM_ABI size_t find(StringRef Str, size_t From = 0) const;
/// Search for the first string \p Str in the string, ignoring case.
///
/// \returns The index of the first occurrence of \p Str, or npos if not
/// found.
- [[nodiscard]] size_t find_insensitive(StringRef Str, size_t From = 0) const;
+ [[nodiscard]] LLVM_ABI size_t find_insensitive(StringRef Str,
+ size_t From = 0) const;
/// Search for the last character \p C in the string.
///
/// \returns The index of the last occurrence of \p C, or npos if not
/// found.
[[nodiscard]] size_t rfind(char C, size_t From = npos) const {
- size_t I = std::min(From, Length);
+ size_t I = std::min(From, size());
while (I) {
--I;
- if (Data[I] == C)
+ if (data()[I] == C)
return I;
}
return npos;
@@ -343,19 +364,20 @@ namespace llvm {
///
/// \returns The index of the last occurrence of \p C, or npos if not
/// found.
- [[nodiscard]] size_t rfind_insensitive(char C, size_t From = npos) const;
+ [[nodiscard]] LLVM_ABI size_t rfind_insensitive(char C,
+ size_t From = npos) const;
/// Search for the last string \p Str in the string.
///
/// \returns The index of the last occurrence of \p Str, or npos if not
/// found.
- [[nodiscard]] size_t rfind(StringRef Str) const;
+ [[nodiscard]] LLVM_ABI size_t rfind(StringRef Str) const;
/// Search for the last string \p Str in the string, ignoring case.
///
/// \returns The index of the last occurrence of \p Str, or npos if not
/// found.
- [[nodiscard]] size_t rfind_insensitive(StringRef Str) const;
+ [[nodiscard]] LLVM_ABI size_t rfind_insensitive(StringRef Str) const;
/// Find the first character in the string that is \p C, or npos if not
/// found. Same as find.
@@ -367,18 +389,20 @@ namespace llvm {
/// not found.
///
/// Complexity: O(size() + Chars.size())
- [[nodiscard]] size_t find_first_of(StringRef Chars, size_t From = 0) const;
+ [[nodiscard]] LLVM_ABI size_t find_first_of(StringRef Chars,
+ size_t From = 0) const;
/// Find the first character in the string that is not \p C or npos if not
/// found.
- [[nodiscard]] size_t find_first_not_of(char C, size_t From = 0) const;
+ [[nodiscard]] LLVM_ABI size_t find_first_not_of(char C,
+ size_t From = 0) const;
/// Find the first character in the string that is not in the string
/// \p Chars, or npos if not found.
///
/// Complexity: O(size() + Chars.size())
- [[nodiscard]] size_t find_first_not_of(StringRef Chars,
- size_t From = 0) const;
+ [[nodiscard]] LLVM_ABI size_t find_first_not_of(StringRef Chars,
+ size_t From = 0) const;
/// Find the last character in the string that is \p C, or npos if not
/// found.
@@ -390,19 +414,20 @@ namespace llvm {
/// found.
///
/// Complexity: O(size() + Chars.size())
- [[nodiscard]] size_t find_last_of(StringRef Chars,
- size_t From = npos) const;
+ [[nodiscard]] LLVM_ABI size_t find_last_of(StringRef Chars,
+ size_t From = npos) const;
/// Find the last character in the string that is not \p C, or npos if not
/// found.
- [[nodiscard]] size_t find_last_not_of(char C, size_t From = npos) const;
+ [[nodiscard]] LLVM_ABI size_t find_last_not_of(char C,
+ size_t From = npos) const;
/// Find the last character in the string that is not in \p Chars, or
/// npos if not found.
///
/// Complexity: O(size() + Chars.size())
- [[nodiscard]] size_t find_last_not_of(StringRef Chars,
- size_t From = npos) const;
+ [[nodiscard]] LLVM_ABI size_t find_last_not_of(StringRef Chars,
+ size_t From = npos) const;
/// Return true if the given string is a substring of *this, and false
/// otherwise.
@@ -435,15 +460,15 @@ namespace llvm {
/// Return the number of occurrences of \p C in the string.
[[nodiscard]] size_t count(char C) const {
size_t Count = 0;
- for (size_t I = 0; I != Length; ++I)
- if (Data[I] == C)
+ for (size_t I = 0; I != size(); ++I)
+ if (data()[I] == C)
++Count;
return Count;
}
/// Return the number of non-overlapped occurrences of \p Str in
/// the string.
- size_t count(StringRef Str) const;
+ LLVM_ABI size_t count(StringRef Str) const;
/// Parse the current string as an integer of the specified radix. If
/// \p Radix is specified as zero, this does radix autosensing using
@@ -508,7 +533,7 @@ namespace llvm {
///
/// APInt::fromString is superficially similar but assumes the
/// string is well-formed in the given radix.
- bool getAsInteger(unsigned Radix, APInt &Result) const;
+ LLVM_ABI bool getAsInteger(unsigned Radix, APInt &Result) const;
/// Parse the current string as an integer of the specified \p Radix. If
/// \p Radix is specified as zero, this does radix autosensing using
@@ -519,7 +544,7 @@ namespace llvm {
/// erroneous if empty.
/// The portion of the string representing the discovered numeric value
/// is removed from the beginning of the string.
- bool consumeInteger(unsigned Radix, APInt &Result);
+ LLVM_ABI bool consumeInteger(unsigned Radix, APInt &Result);
/// Parse the current string as an IEEE double-precision floating
/// point value. The string must be a well-formed double.
@@ -528,17 +553,17 @@ namespace llvm {
/// cannot be represented exactly. Otherwise, the function only fails
/// in case of an overflow or underflow, or an invalid floating point
/// representation.
- bool getAsDouble(double &Result, bool AllowInexact = true) const;
+ LLVM_ABI bool getAsDouble(double &Result, bool AllowInexact = true) const;
/// @}
/// @name String Operations
/// @{
// Convert the given ASCII string to lowercase.
- [[nodiscard]] std::string lower() const;
+ [[nodiscard]] LLVM_ABI std::string lower() const;
/// Convert the given ASCII string to uppercase.
- [[nodiscard]] std::string upper() const;
+ [[nodiscard]] LLVM_ABI std::string upper() const;
/// @}
/// @name Substring Operations
@@ -555,8 +580,8 @@ namespace llvm {
/// suffix (starting with \p Start) will be returned.
[[nodiscard]] constexpr StringRef substr(size_t Start,
size_t N = npos) const {
- Start = std::min(Start, Length);
- return StringRef(Data + Start, std::min(N, Length - Start));
+ Start = std::min(Start, size());
+ return StringRef(data() + Start, std::min(N, size() - Start));
}
/// Return a StringRef equal to 'this' but with only the first \p N
@@ -667,9 +692,9 @@ namespace llvm {
/// will be returned. If this is less than \p Start, an empty string will
/// be returned.
[[nodiscard]] StringRef slice(size_t Start, size_t End) const {
- Start = std::min(Start, Length);
- End = std::clamp(End, Start, Length);
- return StringRef(Data + Start, End - Start);
+ Start = std::min(Start, size());
+ End = std::clamp(End, Start, size());
+ return StringRef(data() + Start, End - Start);
}
/// Split into two substrings around the first occurrence of a separator
@@ -701,7 +726,7 @@ namespace llvm {
size_t Idx = find(Separator);
if (Idx == npos)
return std::make_pair(*this, StringRef());
- return std::make_pair(slice(0, Idx), slice(Idx + Separator.size(), npos));
+ return std::make_pair(slice(0, Idx), substr(Idx + Separator.size()));
}
/// Split into two substrings around the last occurrence of a separator
@@ -719,7 +744,7 @@ namespace llvm {
size_t Idx = rfind(Separator);
if (Idx == npos)
return std::make_pair(*this, StringRef());
- return std::make_pair(slice(0, Idx), slice(Idx + Separator.size(), npos));
+ return std::make_pair(slice(0, Idx), substr(Idx + Separator.size()));
}
/// Split into substrings around the occurrences of a separator string.
@@ -736,9 +761,8 @@ namespace llvm {
/// \param Separator - The string to split on.
/// \param MaxSplit - The maximum number of times the string is split.
/// \param KeepEmpty - True if empty substring should be added.
- void split(SmallVectorImpl &A,
- StringRef Separator, int MaxSplit = -1,
- bool KeepEmpty = true) const;
+ LLVM_ABI void split(SmallVectorImpl &A, StringRef Separator,
+ int MaxSplit = -1, bool KeepEmpty = true) const;
/// Split into substrings around the occurrences of a separator character.
///
@@ -754,8 +778,8 @@ namespace llvm {
/// \param Separator - The string to split on.
/// \param MaxSplit - The maximum number of times the string is split.
/// \param KeepEmpty - True if empty substring should be added.
- void split(SmallVectorImpl &A, char Separator, int MaxSplit = -1,
- bool KeepEmpty = true) const;
+ LLVM_ABI void split(SmallVectorImpl &A, char Separator,
+ int MaxSplit = -1, bool KeepEmpty = true) const;
/// Split into two substrings around the last occurrence of a separator
/// character.
@@ -774,25 +798,25 @@ namespace llvm {
/// Return string with consecutive \p Char characters starting from the
/// the left removed.
[[nodiscard]] StringRef ltrim(char Char) const {
- return drop_front(std::min(Length, find_first_not_of(Char)));
+ return drop_front(std::min(size(), find_first_not_of(Char)));
}
/// Return string with consecutive characters in \p Chars starting from
/// the left removed.
[[nodiscard]] StringRef ltrim(StringRef Chars = " \t\n\v\f\r") const {
- return drop_front(std::min(Length, find_first_not_of(Chars)));
+ return drop_front(std::min(size(), find_first_not_of(Chars)));
}
/// Return string with consecutive \p Char characters starting from the
/// right removed.
[[nodiscard]] StringRef rtrim(char Char) const {
- return drop_back(Length - std::min(Length, find_last_not_of(Char) + 1));
+ return drop_back(size() - std::min(size(), find_last_not_of(Char) + 1));
}
/// Return string with consecutive characters in \p Chars starting from
/// the right removed.
[[nodiscard]] StringRef rtrim(StringRef Chars = " \t\n\v\f\r") const {
- return drop_back(Length - std::min(Length, find_last_not_of(Chars) + 1));
+ return drop_back(size() - std::min(size(), find_last_not_of(Chars) + 1));
}
/// Return string with consecutive \p Char characters starting from the
@@ -819,9 +843,9 @@ namespace llvm {
// If there is no carriage return, assume unix
return "\n";
}
- if (Pos + 1 < Length && Data[Pos + 1] == '\n')
+ if (Pos + 1 < size() && data()[Pos + 1] == '\n')
return "\r\n"; // Windows
- if (Pos > 0 && Data[Pos - 1] == '\n')
+ if (Pos > 0 && data()[Pos - 1] == '\n')
return "\n\r"; // You monster!
return "\r"; // Classic Mac
}
@@ -896,7 +920,7 @@ namespace llvm {
/// @}
/// Compute a hash_code for a StringRef.
- [[nodiscard]] hash_code hash_value(StringRef S);
+ [[nodiscard]] LLVM_ABI hash_code hash_value(StringRef S);
// Provide DenseMapInfo for StringRefs.
template <> struct DenseMapInfo {
@@ -910,7 +934,7 @@ namespace llvm {
reinterpret_cast(~static_cast(1)), 0);
}
- static unsigned getHashValue(StringRef Val);
+ LLVM_ABI static unsigned getHashValue(StringRef Val);
static bool isEqual(StringRef LHS, StringRef RHS) {
if (RHS.data() == getEmptyKey().data())
diff --git a/symbolic-demangle/vendor/swift/include/llvm/ADT/StringSwitch.h b/symbolic-demangle/vendor/swift/include/llvm/ADT/StringSwitch.h
index 7093da076..31297aa85 100644
--- a/symbolic-demangle/vendor/swift/include/llvm/ADT/StringSwitch.h
+++ b/symbolic-demangle/vendor/swift/include/llvm/ADT/StringSwitch.h
@@ -14,9 +14,9 @@
#define LLVM_ADT_STRINGSWITCH_H
#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/Compiler.h"
#include
#include
+#include
#include
namespace llvm {
@@ -67,9 +67,7 @@ class StringSwitch {
// Case-sensitive case matchers
StringSwitch &Case(StringLiteral S, T Value) {
- if (!Result && Str == S) {
- Result = std::move(Value);
- }
+ CaseImpl(Value, S);
return *this;
}
@@ -87,62 +85,65 @@ class StringSwitch {
return *this;
}
+ StringSwitch &Cases(std::initializer_list CaseStrings,
+ T Value) {
+ return CasesImpl(Value, CaseStrings);
+ }
+
StringSwitch &Cases(StringLiteral S0, StringLiteral S1, T Value) {
- return Case(S0, Value).Case(S1, Value);
+ return CasesImpl(Value, {S0, S1});
}
StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
T Value) {
- return Case(S0, Value).Cases(S1, S2, Value);
+ return CasesImpl(Value, {S0, S1, S2});
}
StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
StringLiteral S3, T Value) {
- return Case(S0, Value).Cases(S1, S2, S3, Value);
+ return CasesImpl(Value, {S0, S1, S2, S3});
}
StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
StringLiteral S3, StringLiteral S4, T Value) {
- return Case(S0, Value).Cases(S1, S2, S3, S4, Value);
+ return CasesImpl(Value, {S0, S1, S2, S3, S4});
}
StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
StringLiteral S3, StringLiteral S4, StringLiteral S5,
T Value) {
- return Case(S0, Value).Cases(S1, S2, S3, S4, S5, Value);
+ return CasesImpl(Value, {S0, S1, S2, S3, S4, S5});
}
StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
StringLiteral S3, StringLiteral S4, StringLiteral S5,
StringLiteral S6, T Value) {
- return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, Value);
+ return CasesImpl(Value, {S0, S1, S2, S3, S4, S5, S6});
}
StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
StringLiteral S3, StringLiteral S4, StringLiteral S5,
StringLiteral S6, StringLiteral S7, T Value) {
- return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, Value);
+ return CasesImpl(Value, {S0, S1, S2, S3, S4, S5, S6, S7});
}
StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
StringLiteral S3, StringLiteral S4, StringLiteral S5,
StringLiteral S6, StringLiteral S7, StringLiteral S8,
T Value) {
- return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, S8, Value);
+ return CasesImpl(Value, {S0, S1, S2, S3, S4, S5, S6, S7, S8});
}
StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
StringLiteral S3, StringLiteral S4, StringLiteral S5,
StringLiteral S6, StringLiteral S7, StringLiteral S8,
StringLiteral S9, T Value) {
- return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, S8, S9, Value);
+ return CasesImpl(Value, {S0, S1, S2, S3, S4, S5, S6, S7, S8, S9});
}
// Case-insensitive case matchers.
StringSwitch &CaseLower(StringLiteral S, T Value) {
- if (!Result && Str.equals_insensitive(S))
- Result = std::move(Value);
-
+ CaseLowerImpl(Value, S);
return *this;
}
@@ -160,23 +161,28 @@ class StringSwitch {
return *this;
}
+ StringSwitch &CasesLower(std::initializer_list CaseStrings,
+ T Value) {
+ return CasesLowerImpl(Value, CaseStrings);
+ }
+
StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, T Value) {
- return CaseLower(S0, Value).CaseLower(S1, Value);
+ return CasesLowerImpl(Value, {S0, S1});
}
StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2,
T Value) {
- return CaseLower(S0, Value).CasesLower(S1, S2, Value);
+ return CasesLowerImpl(Value, {S0, S1, S2});
}
StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2,
StringLiteral S3, T Value) {
- return CaseLower(S0, Value).CasesLower(S1, S2, S3, Value);
+ return CasesLowerImpl(Value, {S0, S1, S2, S3});
}
StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2,
StringLiteral S3, StringLiteral S4, T Value) {
- return CaseLower(S0, Value).CasesLower(S1, S2, S3, S4, Value);
+ return CasesLowerImpl(Value, {S0, S1, S2, S3, S4});
}
[[nodiscard]] R Default(T Value) {
@@ -189,6 +195,44 @@ class StringSwitch {
assert(Result && "Fell off the end of a string-switch");
return std::move(*Result);
}
+
+private:
+ // Returns true when `Str` matches the `S` argument, and stores the result.
+ bool CaseImpl(T &Value, StringLiteral S) {
+ if (!Result && Str == S) {
+ Result = std::move(Value);
+ return true;
+ }
+ return false;
+ }
+
+ // Returns true when `Str` matches the `S` argument (case-insensitive), and
+ // stores the result.
+ bool CaseLowerImpl(T &Value, StringLiteral S) {
+ if (!Result && Str.equals_insensitive(S)) {
+ Result = std::move(Value);
+ return true;
+ }
+ return false;
+ }
+
+ StringSwitch &CasesImpl(T &Value,
+ std::initializer_list Cases) {
+ // Stop matching after the string is found.
+ for (StringLiteral S : Cases)
+ if (CaseImpl(Value, S))
+ break;
+ return *this;
+ }
+
+ StringSwitch &CasesLowerImpl(T &Value,
+ std::initializer_list Cases) {
+ // Stop matching after the string is found.
+ for (StringLiteral S : Cases)
+ if (CaseLowerImpl(Value, S))
+ break;
+ return *this;
+ }
};
} // end namespace llvm
diff --git a/symbolic-demangle/vendor/swift/include/llvm/ADT/bit.h b/symbolic-demangle/vendor/swift/include/llvm/ADT/bit.h
index c42b5e686..d6e33c3e6 100644
--- a/symbolic-demangle/vendor/swift/include/llvm/ADT/bit.h
+++ b/symbolic-demangle/vendor/swift/include/llvm/ADT/bit.h
@@ -15,6 +15,7 @@
#define LLVM_ADT_BIT_H
#include "llvm/Support/Compiler.h"
+#include // for std::size_t
#include
#include
#include
@@ -29,7 +30,7 @@
#if defined(__linux__) || defined(__GNU__) || defined(__HAIKU__) || \
defined(__Fuchsia__) || defined(__EMSCRIPTEN__) || defined(__NetBSD__) || \
- defined(__OpenBSD__) || defined(__DragonFly__)
+ defined(__OpenBSD__) || defined(__DragonFly__) || defined(__managarm__)
#include
#elif defined(_AIX)
#include
@@ -147,36 +148,20 @@ template >>
return (Value != 0) && ((Value & (Value - 1)) == 0);
}
-namespace detail {
-template struct TrailingZerosCounter {
- static unsigned count(T Val) {
- if (!Val)
- return std::numeric_limits::digits;
- if (Val & 0x1)
- return 0;
-
- // Bisection method.
- unsigned ZeroBits = 0;
- T Shift = std::numeric_limits::digits >> 1;
- T Mask = std::numeric_limits::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 struct TrailingZerosCounter {
- static unsigned count(T Val) {
- if (Val == 0)
- return 32;
+/// Count number of 0's from the least significant bit to the most
+/// stopping at the first 1.
+///
+/// Only unsigned integral types are allowed.
+///
+/// Returns std::numeric_limits::digits on an input of 0.
+template [[nodiscard]] int countr_zero(T Val) {
+ static_assert(std::is_unsigned_v,
+ "Only unsigned integral types are allowed.");
+ if (!Val)
+ return std::numeric_limits