Add stacktrace symbol demangling
This commit is contained in:
		
							
								
								
									
										4
									
								
								externals/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								externals/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							@@ -154,3 +154,7 @@ endif()
 | 
			
		||||
if (YUZU_USE_EXTERNAL_VULKAN_HEADERS)
 | 
			
		||||
    add_subdirectory(Vulkan-Headers EXCLUDE_FROM_ALL)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
add_library(demangle STATIC)
 | 
			
		||||
target_include_directories(demangle PUBLIC ./demangle)
 | 
			
		||||
target_sources(demangle PRIVATE demangle/ItaniumDemangle.cpp)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										104
									
								
								externals/demangle/Demangle.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								externals/demangle/Demangle.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,104 @@
 | 
			
		||||
//===--- Demangle.h ---------------------------------------------*- 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-FileCopyrightText: Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | 
			
		||||
//
 | 
			
		||||
//===----------------------------------------------------------------------===//
 | 
			
		||||
 | 
			
		||||
#ifndef LLVM_DEMANGLE_DEMANGLE_H
 | 
			
		||||
#define LLVM_DEMANGLE_DEMANGLE_H
 | 
			
		||||
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
namespace llvm {
 | 
			
		||||
/// This is a llvm local version of __cxa_demangle. Other than the name and
 | 
			
		||||
/// being in the llvm namespace it is identical.
 | 
			
		||||
///
 | 
			
		||||
/// The mangled_name is demangled into buf and returned. If the buffer is not
 | 
			
		||||
/// large enough, realloc is used to expand it.
 | 
			
		||||
///
 | 
			
		||||
/// The *status will be set to a value from the following enumeration
 | 
			
		||||
enum : int {
 | 
			
		||||
  demangle_unknown_error = -4,
 | 
			
		||||
  demangle_invalid_args = -3,
 | 
			
		||||
  demangle_invalid_mangled_name = -2,
 | 
			
		||||
  demangle_memory_alloc_failure = -1,
 | 
			
		||||
  demangle_success = 0,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
char *itaniumDemangle(const char *mangled_name, char *buf, size_t *n,
 | 
			
		||||
                      int *status);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
enum MSDemangleFlags {
 | 
			
		||||
  MSDF_None = 0,
 | 
			
		||||
  MSDF_DumpBackrefs = 1 << 0,
 | 
			
		||||
  MSDF_NoAccessSpecifier = 1 << 1,
 | 
			
		||||
  MSDF_NoCallingConvention = 1 << 2,
 | 
			
		||||
  MSDF_NoReturnType = 1 << 3,
 | 
			
		||||
  MSDF_NoMemberType = 1 << 4,
 | 
			
		||||
};
 | 
			
		||||
char *microsoftDemangle(const char *mangled_name, char *buf, size_t *n,
 | 
			
		||||
                        int *status, MSDemangleFlags Flags = MSDF_None);
 | 
			
		||||
 | 
			
		||||
/// "Partial" demangler. This supports demangling a string into an AST
 | 
			
		||||
/// (typically an intermediate stage in itaniumDemangle) and querying certain
 | 
			
		||||
/// properties or partially printing the demangled name.
 | 
			
		||||
struct ItaniumPartialDemangler {
 | 
			
		||||
  ItaniumPartialDemangler();
 | 
			
		||||
 | 
			
		||||
  ItaniumPartialDemangler(ItaniumPartialDemangler &&Other);
 | 
			
		||||
  ItaniumPartialDemangler &operator=(ItaniumPartialDemangler &&Other);
 | 
			
		||||
 | 
			
		||||
  /// Demangle into an AST. Subsequent calls to the rest of the member functions
 | 
			
		||||
  /// implicitly operate on the AST this produces.
 | 
			
		||||
  /// \return true on error, false otherwise
 | 
			
		||||
  bool partialDemangle(const char *MangledName);
 | 
			
		||||
 | 
			
		||||
  /// Just print the entire mangled name into Buf. Buf and N behave like the
 | 
			
		||||
  /// second and third parameters to itaniumDemangle.
 | 
			
		||||
  char *finishDemangle(char *Buf, size_t *N) const;
 | 
			
		||||
 | 
			
		||||
  /// Get the base name of a function. This doesn't include trailing template
 | 
			
		||||
  /// arguments, ie for "a::b<int>" this function returns "b".
 | 
			
		||||
  char *getFunctionBaseName(char *Buf, size_t *N) const;
 | 
			
		||||
 | 
			
		||||
  /// Get the context name for a function. For "a::b::c", this function returns
 | 
			
		||||
  /// "a::b".
 | 
			
		||||
  char *getFunctionDeclContextName(char *Buf, size_t *N) const;
 | 
			
		||||
 | 
			
		||||
  /// Get the entire name of this function.
 | 
			
		||||
  char *getFunctionName(char *Buf, size_t *N) const;
 | 
			
		||||
 | 
			
		||||
  /// Get the parameters for this function.
 | 
			
		||||
  char *getFunctionParameters(char *Buf, size_t *N) const;
 | 
			
		||||
  char *getFunctionReturnType(char *Buf, size_t *N) const;
 | 
			
		||||
 | 
			
		||||
  /// If this function has any any cv or reference qualifiers. These imply that
 | 
			
		||||
  /// the function is a non-static member function.
 | 
			
		||||
  bool hasFunctionQualifiers() const;
 | 
			
		||||
 | 
			
		||||
  /// If this symbol describes a constructor or destructor.
 | 
			
		||||
  bool isCtorOrDtor() const;
 | 
			
		||||
 | 
			
		||||
  /// If this symbol describes a function.
 | 
			
		||||
  bool isFunction() const;
 | 
			
		||||
 | 
			
		||||
  /// If this symbol describes a variable.
 | 
			
		||||
  bool isData() const;
 | 
			
		||||
 | 
			
		||||
  /// If this symbol is a <special-name>. These are generally implicitly
 | 
			
		||||
  /// generated by the implementation, such as vtables and typeinfo names.
 | 
			
		||||
  bool isSpecialName() const;
 | 
			
		||||
 | 
			
		||||
  ~ItaniumPartialDemangler();
 | 
			
		||||
private:
 | 
			
		||||
  void *RootNode;
 | 
			
		||||
  void *Context;
 | 
			
		||||
};
 | 
			
		||||
} // namespace llvm
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										93
									
								
								externals/demangle/DemangleConfig.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								externals/demangle/DemangleConfig.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,93 @@
 | 
			
		||||
//===--- DemangleConfig.h ---------------------------------------*- 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-FileCopyrightText: Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | 
			
		||||
//
 | 
			
		||||
//===----------------------------------------------------------------------===//
 | 
			
		||||
//
 | 
			
		||||
// This file contains a variety of feature test macros copied from
 | 
			
		||||
// include/llvm/Support/Compiler.h so that LLVMDemangle does not need to take
 | 
			
		||||
// a dependency on LLVMSupport.
 | 
			
		||||
//
 | 
			
		||||
//===----------------------------------------------------------------------===//
 | 
			
		||||
 | 
			
		||||
#ifndef LLVM_DEMANGLE_COMPILER_H
 | 
			
		||||
#define LLVM_DEMANGLE_COMPILER_H
 | 
			
		||||
 | 
			
		||||
#ifndef __has_feature
 | 
			
		||||
#define __has_feature(x) 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef __has_cpp_attribute
 | 
			
		||||
#define __has_cpp_attribute(x) 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef __has_attribute
 | 
			
		||||
#define __has_attribute(x) 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef __has_builtin
 | 
			
		||||
#define __has_builtin(x) 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef DEMANGLE_GNUC_PREREQ
 | 
			
		||||
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
 | 
			
		||||
#define DEMANGLE_GNUC_PREREQ(maj, min, patch)                           \
 | 
			
		||||
  ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >=          \
 | 
			
		||||
   ((maj) << 20) + ((min) << 10) + (patch))
 | 
			
		||||
#elif defined(__GNUC__) && defined(__GNUC_MINOR__)
 | 
			
		||||
#define DEMANGLE_GNUC_PREREQ(maj, min, patch)                           \
 | 
			
		||||
  ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10))
 | 
			
		||||
#else
 | 
			
		||||
#define DEMANGLE_GNUC_PREREQ(maj, min, patch) 0
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if __has_attribute(used) || DEMANGLE_GNUC_PREREQ(3, 1, 0)
 | 
			
		||||
#define DEMANGLE_ATTRIBUTE_USED __attribute__((__used__))
 | 
			
		||||
#else
 | 
			
		||||
#define DEMANGLE_ATTRIBUTE_USED
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if __has_builtin(__builtin_unreachable) || DEMANGLE_GNUC_PREREQ(4, 5, 0)
 | 
			
		||||
#define DEMANGLE_UNREACHABLE __builtin_unreachable()
 | 
			
		||||
#elif defined(_MSC_VER)
 | 
			
		||||
#define DEMANGLE_UNREACHABLE __assume(false)
 | 
			
		||||
#else
 | 
			
		||||
#define DEMANGLE_UNREACHABLE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if __has_attribute(noinline) || DEMANGLE_GNUC_PREREQ(3, 4, 0)
 | 
			
		||||
#define DEMANGLE_ATTRIBUTE_NOINLINE __attribute__((noinline))
 | 
			
		||||
#elif defined(_MSC_VER)
 | 
			
		||||
#define DEMANGLE_ATTRIBUTE_NOINLINE __declspec(noinline)
 | 
			
		||||
#else
 | 
			
		||||
#define DEMANGLE_ATTRIBUTE_NOINLINE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if !defined(NDEBUG)
 | 
			
		||||
#define DEMANGLE_DUMP_METHOD DEMANGLE_ATTRIBUTE_NOINLINE DEMANGLE_ATTRIBUTE_USED
 | 
			
		||||
#else
 | 
			
		||||
#define DEMANGLE_DUMP_METHOD DEMANGLE_ATTRIBUTE_NOINLINE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if __cplusplus > 201402L && __has_cpp_attribute(fallthrough)
 | 
			
		||||
#define DEMANGLE_FALLTHROUGH [[fallthrough]]
 | 
			
		||||
#elif __has_cpp_attribute(gnu::fallthrough)
 | 
			
		||||
#define DEMANGLE_FALLTHROUGH [[gnu::fallthrough]]
 | 
			
		||||
#elif !__cplusplus
 | 
			
		||||
// Workaround for llvm.org/PR23435, since clang 3.6 and below emit a spurious
 | 
			
		||||
// error when __has_cpp_attribute is given a scoped attribute in C mode.
 | 
			
		||||
#define DEMANGLE_FALLTHROUGH
 | 
			
		||||
#elif __has_cpp_attribute(clang::fallthrough)
 | 
			
		||||
#define DEMANGLE_FALLTHROUGH [[clang::fallthrough]]
 | 
			
		||||
#else
 | 
			
		||||
#define DEMANGLE_FALLTHROUGH
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define DEMANGLE_NAMESPACE_BEGIN namespace llvm { namespace itanium_demangle {
 | 
			
		||||
#define DEMANGLE_NAMESPACE_END } }
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										588
									
								
								externals/demangle/ItaniumDemangle.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										588
									
								
								externals/demangle/ItaniumDemangle.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,588 @@
 | 
			
		||||
//===------------------------- ItaniumDemangle.cpp ------------------------===//
 | 
			
		||||
//
 | 
			
		||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | 
			
		||||
// See https://llvm.org/LICENSE.txt for license information.
 | 
			
		||||
// SPDX-FileCopyrightText: Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | 
			
		||||
//
 | 
			
		||||
//===----------------------------------------------------------------------===//
 | 
			
		||||
 | 
			
		||||
// FIXME: (possibly) incomplete list of features that clang mangles that this
 | 
			
		||||
// file does not yet support:
 | 
			
		||||
//   - C++ modules TS
 | 
			
		||||
 | 
			
		||||
#include "Demangle.h"
 | 
			
		||||
#include "ItaniumDemangle.h"
 | 
			
		||||
 | 
			
		||||
#include <cassert>
 | 
			
		||||
#include <cctype>
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
#include <cstdlib>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <numeric>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
using namespace llvm;
 | 
			
		||||
using namespace llvm::itanium_demangle;
 | 
			
		||||
 | 
			
		||||
constexpr const char *itanium_demangle::FloatData<float>::spec;
 | 
			
		||||
constexpr const char *itanium_demangle::FloatData<double>::spec;
 | 
			
		||||
constexpr const char *itanium_demangle::FloatData<long double>::spec;
 | 
			
		||||
 | 
			
		||||
// <discriminator> := _ <non-negative number>      # when number < 10
 | 
			
		||||
//                 := __ <non-negative number> _   # when number >= 10
 | 
			
		||||
//  extension      := decimal-digit+               # at the end of string
 | 
			
		||||
const char *itanium_demangle::parse_discriminator(const char *first,
 | 
			
		||||
                                                  const char *last) {
 | 
			
		||||
  // parse but ignore discriminator
 | 
			
		||||
  if (first != last) {
 | 
			
		||||
    if (*first == '_') {
 | 
			
		||||
      const char *t1 = first + 1;
 | 
			
		||||
      if (t1 != last) {
 | 
			
		||||
        if (std::isdigit(*t1))
 | 
			
		||||
          first = t1 + 1;
 | 
			
		||||
        else if (*t1 == '_') {
 | 
			
		||||
          for (++t1; t1 != last && std::isdigit(*t1); ++t1)
 | 
			
		||||
            ;
 | 
			
		||||
          if (t1 != last && *t1 == '_')
 | 
			
		||||
            first = t1 + 1;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    } else if (std::isdigit(*first)) {
 | 
			
		||||
      const char *t1 = first + 1;
 | 
			
		||||
      for (; t1 != last && std::isdigit(*t1); ++t1)
 | 
			
		||||
        ;
 | 
			
		||||
      if (t1 == last)
 | 
			
		||||
        first = last;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return first;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
namespace {
 | 
			
		||||
struct DumpVisitor {
 | 
			
		||||
  unsigned Depth = 0;
 | 
			
		||||
  bool PendingNewline = false;
 | 
			
		||||
 | 
			
		||||
  template<typename NodeT> static constexpr bool wantsNewline(const NodeT *) {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  static bool wantsNewline(NodeArray A) { return !A.empty(); }
 | 
			
		||||
  static constexpr bool wantsNewline(...) { return false; }
 | 
			
		||||
 | 
			
		||||
  template<typename ...Ts> static bool anyWantNewline(Ts ...Vs) {
 | 
			
		||||
    for (bool B : {wantsNewline(Vs)...})
 | 
			
		||||
      if (B)
 | 
			
		||||
        return true;
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void printStr(const char *S) { fprintf(stderr, "%s", S); }
 | 
			
		||||
  void print(StringView SV) {
 | 
			
		||||
    fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.begin());
 | 
			
		||||
  }
 | 
			
		||||
  void print(const Node *N) {
 | 
			
		||||
    if (N)
 | 
			
		||||
      N->visit(std::ref(*this));
 | 
			
		||||
    else
 | 
			
		||||
      printStr("<null>");
 | 
			
		||||
  }
 | 
			
		||||
  void print(NodeOrString NS) {
 | 
			
		||||
    if (NS.isNode())
 | 
			
		||||
      print(NS.asNode());
 | 
			
		||||
    else if (NS.isString())
 | 
			
		||||
      print(NS.asString());
 | 
			
		||||
    else
 | 
			
		||||
      printStr("NodeOrString()");
 | 
			
		||||
  }
 | 
			
		||||
  void print(NodeArray A) {
 | 
			
		||||
    ++Depth;
 | 
			
		||||
    printStr("{");
 | 
			
		||||
    bool First = true;
 | 
			
		||||
    for (const Node *N : A) {
 | 
			
		||||
      if (First)
 | 
			
		||||
        print(N);
 | 
			
		||||
      else
 | 
			
		||||
        printWithComma(N);
 | 
			
		||||
      First = false;
 | 
			
		||||
    }
 | 
			
		||||
    printStr("}");
 | 
			
		||||
    --Depth;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Overload used when T is exactly 'bool', not merely convertible to 'bool'.
 | 
			
		||||
  void print(bool B) { printStr(B ? "true" : "false"); }
 | 
			
		||||
 | 
			
		||||
  template <class T>
 | 
			
		||||
  typename std::enable_if<std::is_unsigned<T>::value>::type print(T N) {
 | 
			
		||||
    fprintf(stderr, "%llu", (unsigned long long)N);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  template <class T>
 | 
			
		||||
  typename std::enable_if<std::is_signed<T>::value>::type print(T N) {
 | 
			
		||||
    fprintf(stderr, "%lld", (long long)N);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void print(ReferenceKind RK) {
 | 
			
		||||
    switch (RK) {
 | 
			
		||||
    case ReferenceKind::LValue:
 | 
			
		||||
      return printStr("ReferenceKind::LValue");
 | 
			
		||||
    case ReferenceKind::RValue:
 | 
			
		||||
      return printStr("ReferenceKind::RValue");
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  void print(FunctionRefQual RQ) {
 | 
			
		||||
    switch (RQ) {
 | 
			
		||||
    case FunctionRefQual::FrefQualNone:
 | 
			
		||||
      return printStr("FunctionRefQual::FrefQualNone");
 | 
			
		||||
    case FunctionRefQual::FrefQualLValue:
 | 
			
		||||
      return printStr("FunctionRefQual::FrefQualLValue");
 | 
			
		||||
    case FunctionRefQual::FrefQualRValue:
 | 
			
		||||
      return printStr("FunctionRefQual::FrefQualRValue");
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  void print(Qualifiers Qs) {
 | 
			
		||||
    if (!Qs) return printStr("QualNone");
 | 
			
		||||
    struct QualName { Qualifiers Q; const char *Name; } Names[] = {
 | 
			
		||||
      {QualConst, "QualConst"},
 | 
			
		||||
      {QualVolatile, "QualVolatile"},
 | 
			
		||||
      {QualRestrict, "QualRestrict"},
 | 
			
		||||
    };
 | 
			
		||||
    for (QualName Name : Names) {
 | 
			
		||||
      if (Qs & Name.Q) {
 | 
			
		||||
        printStr(Name.Name);
 | 
			
		||||
        Qs = Qualifiers(Qs & ~Name.Q);
 | 
			
		||||
        if (Qs) printStr(" | ");
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  void print(SpecialSubKind SSK) {
 | 
			
		||||
    switch (SSK) {
 | 
			
		||||
    case SpecialSubKind::allocator:
 | 
			
		||||
      return printStr("SpecialSubKind::allocator");
 | 
			
		||||
    case SpecialSubKind::basic_string:
 | 
			
		||||
      return printStr("SpecialSubKind::basic_string");
 | 
			
		||||
    case SpecialSubKind::string:
 | 
			
		||||
      return printStr("SpecialSubKind::string");
 | 
			
		||||
    case SpecialSubKind::istream:
 | 
			
		||||
      return printStr("SpecialSubKind::istream");
 | 
			
		||||
    case SpecialSubKind::ostream:
 | 
			
		||||
      return printStr("SpecialSubKind::ostream");
 | 
			
		||||
    case SpecialSubKind::iostream:
 | 
			
		||||
      return printStr("SpecialSubKind::iostream");
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  void print(TemplateParamKind TPK) {
 | 
			
		||||
    switch (TPK) {
 | 
			
		||||
    case TemplateParamKind::Type:
 | 
			
		||||
      return printStr("TemplateParamKind::Type");
 | 
			
		||||
    case TemplateParamKind::NonType:
 | 
			
		||||
      return printStr("TemplateParamKind::NonType");
 | 
			
		||||
    case TemplateParamKind::Template:
 | 
			
		||||
      return printStr("TemplateParamKind::Template");
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void newLine() {
 | 
			
		||||
    printStr("\n");
 | 
			
		||||
    for (unsigned I = 0; I != Depth; ++I)
 | 
			
		||||
      printStr(" ");
 | 
			
		||||
    PendingNewline = false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  template<typename T> void printWithPendingNewline(T V) {
 | 
			
		||||
    print(V);
 | 
			
		||||
    if (wantsNewline(V))
 | 
			
		||||
      PendingNewline = true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  template<typename T> void printWithComma(T V) {
 | 
			
		||||
    if (PendingNewline || wantsNewline(V)) {
 | 
			
		||||
      printStr(",");
 | 
			
		||||
      newLine();
 | 
			
		||||
    } else {
 | 
			
		||||
      printStr(", ");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    printWithPendingNewline(V);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  struct CtorArgPrinter {
 | 
			
		||||
    DumpVisitor &Visitor;
 | 
			
		||||
 | 
			
		||||
    template<typename T, typename ...Rest> void operator()(T V, Rest ...Vs) {
 | 
			
		||||
      if (Visitor.anyWantNewline(V, Vs...))
 | 
			
		||||
        Visitor.newLine();
 | 
			
		||||
      Visitor.printWithPendingNewline(V);
 | 
			
		||||
      int PrintInOrder[] = { (Visitor.printWithComma(Vs), 0)..., 0 };
 | 
			
		||||
      (void)PrintInOrder;
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  template<typename NodeT> void operator()(const NodeT *Node) {
 | 
			
		||||
    Depth += 2;
 | 
			
		||||
    fprintf(stderr, "%s(", itanium_demangle::NodeKind<NodeT>::name());
 | 
			
		||||
    Node->match(CtorArgPrinter{*this});
 | 
			
		||||
    fprintf(stderr, ")");
 | 
			
		||||
    Depth -= 2;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void operator()(const ForwardTemplateReference *Node) {
 | 
			
		||||
    Depth += 2;
 | 
			
		||||
    fprintf(stderr, "ForwardTemplateReference(");
 | 
			
		||||
    if (Node->Ref && !Node->Printing) {
 | 
			
		||||
      Node->Printing = true;
 | 
			
		||||
      CtorArgPrinter{*this}(Node->Ref);
 | 
			
		||||
      Node->Printing = false;
 | 
			
		||||
    } else {
 | 
			
		||||
      CtorArgPrinter{*this}(Node->Index);
 | 
			
		||||
    }
 | 
			
		||||
    fprintf(stderr, ")");
 | 
			
		||||
    Depth -= 2;
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void itanium_demangle::Node::dump() const {
 | 
			
		||||
  DumpVisitor V;
 | 
			
		||||
  visit(std::ref(V));
 | 
			
		||||
  V.newLine();
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
class BumpPointerAllocator {
 | 
			
		||||
  struct BlockMeta {
 | 
			
		||||
    BlockMeta* Next;
 | 
			
		||||
    size_t Current;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  static constexpr size_t AllocSize = 4096;
 | 
			
		||||
  static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta);
 | 
			
		||||
 | 
			
		||||
  alignas(long double) char InitialBuffer[AllocSize];
 | 
			
		||||
  BlockMeta* BlockList = nullptr;
 | 
			
		||||
 | 
			
		||||
  void grow() {
 | 
			
		||||
    char* NewMeta = static_cast<char *>(std::malloc(AllocSize));
 | 
			
		||||
    if (NewMeta == nullptr)
 | 
			
		||||
      std::terminate();
 | 
			
		||||
    BlockList = new (NewMeta) BlockMeta{BlockList, 0};
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void* allocateMassive(size_t NBytes) {
 | 
			
		||||
    NBytes += sizeof(BlockMeta);
 | 
			
		||||
    BlockMeta* NewMeta = reinterpret_cast<BlockMeta*>(std::malloc(NBytes));
 | 
			
		||||
    if (NewMeta == nullptr)
 | 
			
		||||
      std::terminate();
 | 
			
		||||
    BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0};
 | 
			
		||||
    return static_cast<void*>(NewMeta + 1);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  BumpPointerAllocator()
 | 
			
		||||
      : BlockList(new (InitialBuffer) BlockMeta{nullptr, 0}) {}
 | 
			
		||||
 | 
			
		||||
  void* allocate(size_t N) {
 | 
			
		||||
    N = (N + 15u) & ~15u;
 | 
			
		||||
    if (N + BlockList->Current >= UsableAllocSize) {
 | 
			
		||||
      if (N > UsableAllocSize)
 | 
			
		||||
        return allocateMassive(N);
 | 
			
		||||
      grow();
 | 
			
		||||
    }
 | 
			
		||||
    BlockList->Current += N;
 | 
			
		||||
    return static_cast<void*>(reinterpret_cast<char*>(BlockList + 1) +
 | 
			
		||||
                              BlockList->Current - N);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void reset() {
 | 
			
		||||
    while (BlockList) {
 | 
			
		||||
      BlockMeta* Tmp = BlockList;
 | 
			
		||||
      BlockList = BlockList->Next;
 | 
			
		||||
      if (reinterpret_cast<char*>(Tmp) != InitialBuffer)
 | 
			
		||||
        std::free(Tmp);
 | 
			
		||||
    }
 | 
			
		||||
    BlockList = new (InitialBuffer) BlockMeta{nullptr, 0};
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ~BumpPointerAllocator() { reset(); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class DefaultAllocator {
 | 
			
		||||
  BumpPointerAllocator Alloc;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  void reset() { Alloc.reset(); }
 | 
			
		||||
 | 
			
		||||
  template<typename T, typename ...Args> T *makeNode(Args &&...args) {
 | 
			
		||||
    return new (Alloc.allocate(sizeof(T)))
 | 
			
		||||
        T(std::forward<Args>(args)...);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void *allocateNodeArray(size_t sz) {
 | 
			
		||||
    return Alloc.allocate(sizeof(Node *) * sz);
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
}  // unnamed namespace
 | 
			
		||||
 | 
			
		||||
//===----------------------------------------------------------------------===//
 | 
			
		||||
// Code beyond this point should not be synchronized with libc++abi.
 | 
			
		||||
//===----------------------------------------------------------------------===//
 | 
			
		||||
 | 
			
		||||
using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>;
 | 
			
		||||
 | 
			
		||||
char *llvm::itaniumDemangle(const char *MangledName, char *Buf,
 | 
			
		||||
                            size_t *N, int *Status) {
 | 
			
		||||
  if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) {
 | 
			
		||||
    if (Status)
 | 
			
		||||
      *Status = demangle_invalid_args;
 | 
			
		||||
    return nullptr;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  int InternalStatus = demangle_success;
 | 
			
		||||
  Demangler Parser(MangledName, MangledName + std::strlen(MangledName));
 | 
			
		||||
  OutputStream S;
 | 
			
		||||
 | 
			
		||||
  Node *AST = Parser.parse();
 | 
			
		||||
 | 
			
		||||
  if (AST == nullptr)
 | 
			
		||||
    InternalStatus = demangle_invalid_mangled_name;
 | 
			
		||||
  else if (!initializeOutputStream(Buf, N, S, 1024))
 | 
			
		||||
    InternalStatus = demangle_memory_alloc_failure;
 | 
			
		||||
  else {
 | 
			
		||||
    assert(Parser.ForwardTemplateRefs.empty());
 | 
			
		||||
    AST->print(S);
 | 
			
		||||
    S += '\0';
 | 
			
		||||
    if (N != nullptr)
 | 
			
		||||
      *N = S.getCurrentPosition();
 | 
			
		||||
    Buf = S.getBuffer();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (Status)
 | 
			
		||||
    *Status = InternalStatus;
 | 
			
		||||
  return InternalStatus == demangle_success ? Buf : nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ItaniumPartialDemangler::ItaniumPartialDemangler()
 | 
			
		||||
    : RootNode(nullptr), Context(new Demangler{nullptr, nullptr}) {}
 | 
			
		||||
 | 
			
		||||
ItaniumPartialDemangler::~ItaniumPartialDemangler() {
 | 
			
		||||
  delete static_cast<Demangler *>(Context);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ItaniumPartialDemangler::ItaniumPartialDemangler(
 | 
			
		||||
    ItaniumPartialDemangler &&Other)
 | 
			
		||||
    : RootNode(Other.RootNode), Context(Other.Context) {
 | 
			
		||||
  Other.Context = Other.RootNode = nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ItaniumPartialDemangler &ItaniumPartialDemangler::
 | 
			
		||||
operator=(ItaniumPartialDemangler &&Other) {
 | 
			
		||||
  std::swap(RootNode, Other.RootNode);
 | 
			
		||||
  std::swap(Context, Other.Context);
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Demangle MangledName into an AST, storing it into this->RootNode.
 | 
			
		||||
bool ItaniumPartialDemangler::partialDemangle(const char *MangledName) {
 | 
			
		||||
  Demangler *Parser = static_cast<Demangler *>(Context);
 | 
			
		||||
  size_t Len = std::strlen(MangledName);
 | 
			
		||||
  Parser->reset(MangledName, MangledName + Len);
 | 
			
		||||
  RootNode = Parser->parse();
 | 
			
		||||
  return RootNode == nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *printNode(const Node *RootNode, char *Buf, size_t *N) {
 | 
			
		||||
  OutputStream S;
 | 
			
		||||
  if (!initializeOutputStream(Buf, N, S, 128))
 | 
			
		||||
    return nullptr;
 | 
			
		||||
  RootNode->print(S);
 | 
			
		||||
  S += '\0';
 | 
			
		||||
  if (N != nullptr)
 | 
			
		||||
    *N = S.getCurrentPosition();
 | 
			
		||||
  return S.getBuffer();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const {
 | 
			
		||||
  if (!isFunction())
 | 
			
		||||
    return nullptr;
 | 
			
		||||
 | 
			
		||||
  const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName();
 | 
			
		||||
 | 
			
		||||
  while (true) {
 | 
			
		||||
    switch (Name->getKind()) {
 | 
			
		||||
    case Node::KAbiTagAttr:
 | 
			
		||||
      Name = static_cast<const AbiTagAttr *>(Name)->Base;
 | 
			
		||||
      continue;
 | 
			
		||||
    case Node::KStdQualifiedName:
 | 
			
		||||
      Name = static_cast<const StdQualifiedName *>(Name)->Child;
 | 
			
		||||
      continue;
 | 
			
		||||
    case Node::KNestedName:
 | 
			
		||||
      Name = static_cast<const NestedName *>(Name)->Name;
 | 
			
		||||
      continue;
 | 
			
		||||
    case Node::KLocalName:
 | 
			
		||||
      Name = static_cast<const LocalName *>(Name)->Entity;
 | 
			
		||||
      continue;
 | 
			
		||||
    case Node::KNameWithTemplateArgs:
 | 
			
		||||
      Name = static_cast<const NameWithTemplateArgs *>(Name)->Name;
 | 
			
		||||
      continue;
 | 
			
		||||
    default:
 | 
			
		||||
      return printNode(Name, Buf, N);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf,
 | 
			
		||||
                                                          size_t *N) const {
 | 
			
		||||
  if (!isFunction())
 | 
			
		||||
    return nullptr;
 | 
			
		||||
  const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName();
 | 
			
		||||
 | 
			
		||||
  OutputStream S;
 | 
			
		||||
  if (!initializeOutputStream(Buf, N, S, 128))
 | 
			
		||||
    return nullptr;
 | 
			
		||||
 | 
			
		||||
 KeepGoingLocalFunction:
 | 
			
		||||
  while (true) {
 | 
			
		||||
    if (Name->getKind() == Node::KAbiTagAttr) {
 | 
			
		||||
      Name = static_cast<const AbiTagAttr *>(Name)->Base;
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
    if (Name->getKind() == Node::KNameWithTemplateArgs) {
 | 
			
		||||
      Name = static_cast<const NameWithTemplateArgs *>(Name)->Name;
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
    break;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  switch (Name->getKind()) {
 | 
			
		||||
  case Node::KStdQualifiedName:
 | 
			
		||||
    S += "std";
 | 
			
		||||
    break;
 | 
			
		||||
  case Node::KNestedName:
 | 
			
		||||
    static_cast<const NestedName *>(Name)->Qual->print(S);
 | 
			
		||||
    break;
 | 
			
		||||
  case Node::KLocalName: {
 | 
			
		||||
    auto *LN = static_cast<const LocalName *>(Name);
 | 
			
		||||
    LN->Encoding->print(S);
 | 
			
		||||
    S += "::";
 | 
			
		||||
    Name = LN->Entity;
 | 
			
		||||
    goto KeepGoingLocalFunction;
 | 
			
		||||
  }
 | 
			
		||||
  default:
 | 
			
		||||
    break;
 | 
			
		||||
  }
 | 
			
		||||
  S += '\0';
 | 
			
		||||
  if (N != nullptr)
 | 
			
		||||
    *N = S.getCurrentPosition();
 | 
			
		||||
  return S.getBuffer();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char *ItaniumPartialDemangler::getFunctionName(char *Buf, size_t *N) const {
 | 
			
		||||
  if (!isFunction())
 | 
			
		||||
    return nullptr;
 | 
			
		||||
  auto *Name = static_cast<FunctionEncoding *>(RootNode)->getName();
 | 
			
		||||
  return printNode(Name, Buf, N);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char *ItaniumPartialDemangler::getFunctionParameters(char *Buf,
 | 
			
		||||
                                                     size_t *N) const {
 | 
			
		||||
  if (!isFunction())
 | 
			
		||||
    return nullptr;
 | 
			
		||||
  NodeArray Params = static_cast<FunctionEncoding *>(RootNode)->getParams();
 | 
			
		||||
 | 
			
		||||
  OutputStream S;
 | 
			
		||||
  if (!initializeOutputStream(Buf, N, S, 128))
 | 
			
		||||
    return nullptr;
 | 
			
		||||
 | 
			
		||||
  S += '(';
 | 
			
		||||
  Params.printWithComma(S);
 | 
			
		||||
  S += ')';
 | 
			
		||||
  S += '\0';
 | 
			
		||||
  if (N != nullptr)
 | 
			
		||||
    *N = S.getCurrentPosition();
 | 
			
		||||
  return S.getBuffer();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char *ItaniumPartialDemangler::getFunctionReturnType(
 | 
			
		||||
    char *Buf, size_t *N) const {
 | 
			
		||||
  if (!isFunction())
 | 
			
		||||
    return nullptr;
 | 
			
		||||
 | 
			
		||||
  OutputStream S;
 | 
			
		||||
  if (!initializeOutputStream(Buf, N, S, 128))
 | 
			
		||||
    return nullptr;
 | 
			
		||||
 | 
			
		||||
  if (const Node *Ret =
 | 
			
		||||
          static_cast<const FunctionEncoding *>(RootNode)->getReturnType())
 | 
			
		||||
    Ret->print(S);
 | 
			
		||||
 | 
			
		||||
  S += '\0';
 | 
			
		||||
  if (N != nullptr)
 | 
			
		||||
    *N = S.getCurrentPosition();
 | 
			
		||||
  return S.getBuffer();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char *ItaniumPartialDemangler::finishDemangle(char *Buf, size_t *N) const {
 | 
			
		||||
  assert(RootNode != nullptr && "must call partialDemangle()");
 | 
			
		||||
  return printNode(static_cast<Node *>(RootNode), Buf, N);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ItaniumPartialDemangler::hasFunctionQualifiers() const {
 | 
			
		||||
  assert(RootNode != nullptr && "must call partialDemangle()");
 | 
			
		||||
  if (!isFunction())
 | 
			
		||||
    return false;
 | 
			
		||||
  auto *E = static_cast<const FunctionEncoding *>(RootNode);
 | 
			
		||||
  return E->getCVQuals() != QualNone || E->getRefQual() != FrefQualNone;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ItaniumPartialDemangler::isCtorOrDtor() const {
 | 
			
		||||
  const Node *N = static_cast<const Node *>(RootNode);
 | 
			
		||||
  while (N) {
 | 
			
		||||
    switch (N->getKind()) {
 | 
			
		||||
    default:
 | 
			
		||||
      return false;
 | 
			
		||||
    case Node::KCtorDtorName:
 | 
			
		||||
      return true;
 | 
			
		||||
 | 
			
		||||
    case Node::KAbiTagAttr:
 | 
			
		||||
      N = static_cast<const AbiTagAttr *>(N)->Base;
 | 
			
		||||
      break;
 | 
			
		||||
    case Node::KFunctionEncoding:
 | 
			
		||||
      N = static_cast<const FunctionEncoding *>(N)->getName();
 | 
			
		||||
      break;
 | 
			
		||||
    case Node::KLocalName:
 | 
			
		||||
      N = static_cast<const LocalName *>(N)->Entity;
 | 
			
		||||
      break;
 | 
			
		||||
    case Node::KNameWithTemplateArgs:
 | 
			
		||||
      N = static_cast<const NameWithTemplateArgs *>(N)->Name;
 | 
			
		||||
      break;
 | 
			
		||||
    case Node::KNestedName:
 | 
			
		||||
      N = static_cast<const NestedName *>(N)->Name;
 | 
			
		||||
      break;
 | 
			
		||||
    case Node::KStdQualifiedName:
 | 
			
		||||
      N = static_cast<const StdQualifiedName *>(N)->Child;
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ItaniumPartialDemangler::isFunction() const {
 | 
			
		||||
  assert(RootNode != nullptr && "must call partialDemangle()");
 | 
			
		||||
  return static_cast<const Node *>(RootNode)->getKind() ==
 | 
			
		||||
         Node::KFunctionEncoding;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ItaniumPartialDemangler::isSpecialName() const {
 | 
			
		||||
  assert(RootNode != nullptr && "must call partialDemangle()");
 | 
			
		||||
  auto K = static_cast<const Node *>(RootNode)->getKind();
 | 
			
		||||
  return K == Node::KSpecialName || K == Node::KCtorVtableSpecialName;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ItaniumPartialDemangler::isData() const {
 | 
			
		||||
  return !isFunction() && !isSpecialName();
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										5582
									
								
								externals/demangle/ItaniumDemangle.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5582
									
								
								externals/demangle/ItaniumDemangle.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										279
									
								
								externals/demangle/LICENSE.TXT
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										279
									
								
								externals/demangle/LICENSE.TXT
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,279 @@
 | 
			
		||||
==============================================================================
 | 
			
		||||
The LLVM Project is under the Apache License v2.0 with LLVM Exceptions:
 | 
			
		||||
==============================================================================
 | 
			
		||||
 | 
			
		||||
                                 Apache License
 | 
			
		||||
                           Version 2.0, January 2004
 | 
			
		||||
                        http://www.apache.org/licenses/
 | 
			
		||||
 | 
			
		||||
    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 | 
			
		||||
 | 
			
		||||
    1. Definitions.
 | 
			
		||||
 | 
			
		||||
      "License" shall mean the terms and conditions for use, reproduction,
 | 
			
		||||
      and distribution as defined by Sections 1 through 9 of this document.
 | 
			
		||||
 | 
			
		||||
      "Licensor" shall mean the copyright owner or entity authorized by
 | 
			
		||||
      the copyright owner that is granting the License.
 | 
			
		||||
 | 
			
		||||
      "Legal Entity" shall mean the union of the acting entity and all
 | 
			
		||||
      other entities that control, are controlled by, or are under common
 | 
			
		||||
      control with that entity. For the purposes of this definition,
 | 
			
		||||
      "control" means (i) the power, direct or indirect, to cause the
 | 
			
		||||
      direction or management of such entity, whether by contract or
 | 
			
		||||
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
 | 
			
		||||
      outstanding shares, or (iii) beneficial ownership of such entity.
 | 
			
		||||
 | 
			
		||||
      "You" (or "Your") shall mean an individual or Legal Entity
 | 
			
		||||
      exercising permissions granted by this License.
 | 
			
		||||
 | 
			
		||||
      "Source" form shall mean the preferred form for making modifications,
 | 
			
		||||
      including but not limited to software source code, documentation
 | 
			
		||||
      source, and configuration files.
 | 
			
		||||
 | 
			
		||||
      "Object" form shall mean any form resulting from mechanical
 | 
			
		||||
      transformation or translation of a Source form, including but
 | 
			
		||||
      not limited to compiled object code, generated documentation,
 | 
			
		||||
      and conversions to other media types.
 | 
			
		||||
 | 
			
		||||
      "Work" shall mean the work of authorship, whether in Source or
 | 
			
		||||
      Object form, made available under the License, as indicated by a
 | 
			
		||||
      copyright notice that is included in or attached to the work
 | 
			
		||||
      (an example is provided in the Appendix below).
 | 
			
		||||
 | 
			
		||||
      "Derivative Works" shall mean any work, whether in Source or Object
 | 
			
		||||
      form, that is based on (or derived from) the Work and for which the
 | 
			
		||||
      editorial revisions, annotations, elaborations, or other modifications
 | 
			
		||||
      represent, as a whole, an original work of authorship. For the purposes
 | 
			
		||||
      of this License, Derivative Works shall not include works that remain
 | 
			
		||||
      separable from, or merely link (or bind by name) to the interfaces of,
 | 
			
		||||
      the Work and Derivative Works thereof.
 | 
			
		||||
 | 
			
		||||
      "Contribution" shall mean any work of authorship, including
 | 
			
		||||
      the original version of the Work and any modifications or additions
 | 
			
		||||
      to that Work or Derivative Works thereof, that is intentionally
 | 
			
		||||
      submitted to Licensor for inclusion in the Work by the copyright owner
 | 
			
		||||
      or by an individual or Legal Entity authorized to submit on behalf of
 | 
			
		||||
      the copyright owner. For the purposes of this definition, "submitted"
 | 
			
		||||
      means any form of electronic, verbal, or written communication sent
 | 
			
		||||
      to the Licensor or its representatives, including but not limited to
 | 
			
		||||
      communication on electronic mailing lists, source code control systems,
 | 
			
		||||
      and issue tracking systems that are managed by, or on behalf of, the
 | 
			
		||||
      Licensor for the purpose of discussing and improving the Work, but
 | 
			
		||||
      excluding communication that is conspicuously marked or otherwise
 | 
			
		||||
      designated in writing by the copyright owner as "Not a Contribution."
 | 
			
		||||
 | 
			
		||||
      "Contributor" shall mean Licensor and any individual or Legal Entity
 | 
			
		||||
      on behalf of whom a Contribution has been received by Licensor and
 | 
			
		||||
      subsequently incorporated within the Work.
 | 
			
		||||
 | 
			
		||||
    2. Grant of Copyright License. Subject to the terms and conditions of
 | 
			
		||||
      this License, each Contributor hereby grants to You a perpetual,
 | 
			
		||||
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 | 
			
		||||
      copyright license to reproduce, prepare Derivative Works of,
 | 
			
		||||
      publicly display, publicly perform, sublicense, and distribute the
 | 
			
		||||
      Work and such Derivative Works in Source or Object form.
 | 
			
		||||
 | 
			
		||||
    3. Grant of Patent License. Subject to the terms and conditions of
 | 
			
		||||
      this License, each Contributor hereby grants to You a perpetual,
 | 
			
		||||
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 | 
			
		||||
      (except as stated in this section) patent license to make, have made,
 | 
			
		||||
      use, offer to sell, sell, import, and otherwise transfer the Work,
 | 
			
		||||
      where such license applies only to those patent claims licensable
 | 
			
		||||
      by such Contributor that are necessarily infringed by their
 | 
			
		||||
      Contribution(s) alone or by combination of their Contribution(s)
 | 
			
		||||
      with the Work to which such Contribution(s) was submitted. If You
 | 
			
		||||
      institute patent litigation against any entity (including a
 | 
			
		||||
      cross-claim or counterclaim in a lawsuit) alleging that the Work
 | 
			
		||||
      or a Contribution incorporated within the Work constitutes direct
 | 
			
		||||
      or contributory patent infringement, then any patent licenses
 | 
			
		||||
      granted to You under this License for that Work shall terminate
 | 
			
		||||
      as of the date such litigation is filed.
 | 
			
		||||
 | 
			
		||||
    4. Redistribution. You may reproduce and distribute copies of the
 | 
			
		||||
      Work or Derivative Works thereof in any medium, with or without
 | 
			
		||||
      modifications, and in Source or Object form, provided that You
 | 
			
		||||
      meet the following conditions:
 | 
			
		||||
 | 
			
		||||
      (a) You must give any other recipients of the Work or
 | 
			
		||||
          Derivative Works a copy of this License; and
 | 
			
		||||
 | 
			
		||||
      (b) You must cause any modified files to carry prominent notices
 | 
			
		||||
          stating that You changed the files; and
 | 
			
		||||
 | 
			
		||||
      (c) You must retain, in the Source form of any Derivative Works
 | 
			
		||||
          that You distribute, all copyright, patent, trademark, and
 | 
			
		||||
          attribution notices from the Source form of the Work,
 | 
			
		||||
          excluding those notices that do not pertain to any part of
 | 
			
		||||
          the Derivative Works; and
 | 
			
		||||
 | 
			
		||||
      (d) If the Work includes a "NOTICE" text file as part of its
 | 
			
		||||
          distribution, then any Derivative Works that You distribute must
 | 
			
		||||
          include a readable copy of the attribution notices contained
 | 
			
		||||
          within such NOTICE file, excluding those notices that do not
 | 
			
		||||
          pertain to any part of the Derivative Works, in at least one
 | 
			
		||||
          of the following places: within a NOTICE text file distributed
 | 
			
		||||
          as part of the Derivative Works; within the Source form or
 | 
			
		||||
          documentation, if provided along with the Derivative Works; or,
 | 
			
		||||
          within a display generated by the Derivative Works, if and
 | 
			
		||||
          wherever such third-party notices normally appear. The contents
 | 
			
		||||
          of the NOTICE file are for informational purposes only and
 | 
			
		||||
          do not modify the License. You may add Your own attribution
 | 
			
		||||
          notices within Derivative Works that You distribute, alongside
 | 
			
		||||
          or as an addendum to the NOTICE text from the Work, provided
 | 
			
		||||
          that such additional attribution notices cannot be construed
 | 
			
		||||
          as modifying the License.
 | 
			
		||||
 | 
			
		||||
      You may add Your own copyright statement to Your modifications and
 | 
			
		||||
      may provide additional or different license terms and conditions
 | 
			
		||||
      for use, reproduction, or distribution of Your modifications, or
 | 
			
		||||
      for any such Derivative Works as a whole, provided Your use,
 | 
			
		||||
      reproduction, and distribution of the Work otherwise complies with
 | 
			
		||||
      the conditions stated in this License.
 | 
			
		||||
 | 
			
		||||
    5. Submission of Contributions. Unless You explicitly state otherwise,
 | 
			
		||||
      any Contribution intentionally submitted for inclusion in the Work
 | 
			
		||||
      by You to the Licensor shall be under the terms and conditions of
 | 
			
		||||
      this License, without any additional terms or conditions.
 | 
			
		||||
      Notwithstanding the above, nothing herein shall supersede or modify
 | 
			
		||||
      the terms of any separate license agreement you may have executed
 | 
			
		||||
      with Licensor regarding such Contributions.
 | 
			
		||||
 | 
			
		||||
    6. Trademarks. This License does not grant permission to use the trade
 | 
			
		||||
      names, trademarks, service marks, or product names of the Licensor,
 | 
			
		||||
      except as required for reasonable and customary use in describing the
 | 
			
		||||
      origin of the Work and reproducing the content of the NOTICE file.
 | 
			
		||||
 | 
			
		||||
    7. Disclaimer of Warranty. Unless required by applicable law or
 | 
			
		||||
      agreed to in writing, Licensor provides the Work (and each
 | 
			
		||||
      Contributor provides its Contributions) on an "AS IS" BASIS,
 | 
			
		||||
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 | 
			
		||||
      implied, including, without limitation, any warranties or conditions
 | 
			
		||||
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
 | 
			
		||||
      PARTICULAR PURPOSE. You are solely responsible for determining the
 | 
			
		||||
      appropriateness of using or redistributing the Work and assume any
 | 
			
		||||
      risks associated with Your exercise of permissions under this License.
 | 
			
		||||
 | 
			
		||||
    8. Limitation of Liability. In no event and under no legal theory,
 | 
			
		||||
      whether in tort (including negligence), contract, or otherwise,
 | 
			
		||||
      unless required by applicable law (such as deliberate and grossly
 | 
			
		||||
      negligent acts) or agreed to in writing, shall any Contributor be
 | 
			
		||||
      liable to You for damages, including any direct, indirect, special,
 | 
			
		||||
      incidental, or consequential damages of any character arising as a
 | 
			
		||||
      result of this License or out of the use or inability to use the
 | 
			
		||||
      Work (including but not limited to damages for loss of goodwill,
 | 
			
		||||
      work stoppage, computer failure or malfunction, or any and all
 | 
			
		||||
      other commercial damages or losses), even if such Contributor
 | 
			
		||||
      has been advised of the possibility of such damages.
 | 
			
		||||
 | 
			
		||||
    9. Accepting Warranty or Additional Liability. While redistributing
 | 
			
		||||
      the Work or Derivative Works thereof, You may choose to offer,
 | 
			
		||||
      and charge a fee for, acceptance of support, warranty, indemnity,
 | 
			
		||||
      or other liability obligations and/or rights consistent with this
 | 
			
		||||
      License. However, in accepting such obligations, You may act only
 | 
			
		||||
      on Your own behalf and on Your sole responsibility, not on behalf
 | 
			
		||||
      of any other Contributor, and only if You agree to indemnify,
 | 
			
		||||
      defend, and hold each Contributor harmless for any liability
 | 
			
		||||
      incurred by, or claims asserted against, such Contributor by reason
 | 
			
		||||
      of your accepting any such warranty or additional liability.
 | 
			
		||||
 | 
			
		||||
    END OF TERMS AND CONDITIONS
 | 
			
		||||
 | 
			
		||||
    APPENDIX: How to apply the Apache License to your work.
 | 
			
		||||
 | 
			
		||||
      To apply the Apache License to your work, attach the following
 | 
			
		||||
      boilerplate notice, with the fields enclosed by brackets "[]"
 | 
			
		||||
      replaced with your own identifying information. (Don't include
 | 
			
		||||
      the brackets!)  The text should be enclosed in the appropriate
 | 
			
		||||
      comment syntax for the file format. We also recommend that a
 | 
			
		||||
      file or class name and description of purpose be included on the
 | 
			
		||||
      same "printed page" as the copyright notice for easier
 | 
			
		||||
      identification within third-party archives.
 | 
			
		||||
 | 
			
		||||
    Copyright [yyyy] [name of copyright owner]
 | 
			
		||||
 | 
			
		||||
    Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
    you may not use this file except in compliance with the License.
 | 
			
		||||
    You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
       http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
    Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
    distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
    See the License for the specific language governing permissions and
 | 
			
		||||
    limitations under the License.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
---- LLVM Exceptions to the Apache 2.0 License ----
 | 
			
		||||
 | 
			
		||||
As an exception, if, as a result of your compiling your source code, portions
 | 
			
		||||
of this Software are embedded into an Object form of such source code, you
 | 
			
		||||
may redistribute such embedded portions in such Object form without complying
 | 
			
		||||
with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
 | 
			
		||||
 | 
			
		||||
In addition, if you combine or link compiled forms of this Software with
 | 
			
		||||
software that is licensed under the GPLv2 ("Combined Software") and if a
 | 
			
		||||
court of competent jurisdiction determines that the patent provision (Section
 | 
			
		||||
3), the indemnity provision (Section 9) or other Section of the License
 | 
			
		||||
conflicts with the conditions of the GPLv2, you may retroactively and
 | 
			
		||||
prospectively choose to deem waived or otherwise exclude such Section(s) of
 | 
			
		||||
the License, but only in their entirety and only with respect to the Combined
 | 
			
		||||
Software.
 | 
			
		||||
 | 
			
		||||
==============================================================================
 | 
			
		||||
Software from third parties included in the LLVM Project:
 | 
			
		||||
==============================================================================
 | 
			
		||||
The LLVM Project contains third party software which is under different license
 | 
			
		||||
terms. All such code will be identified clearly using at least one of two
 | 
			
		||||
mechanisms:
 | 
			
		||||
1) It will be in a separate directory tree with its own `LICENSE.txt` or
 | 
			
		||||
   `LICENSE` file at the top containing the specific license and restrictions
 | 
			
		||||
   which apply to that software, or
 | 
			
		||||
2) It will contain specific license and restriction terms at the top of every
 | 
			
		||||
   file.
 | 
			
		||||
 | 
			
		||||
==============================================================================
 | 
			
		||||
Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy):
 | 
			
		||||
==============================================================================
 | 
			
		||||
University of Illinois/NCSA
 | 
			
		||||
Open Source License
 | 
			
		||||
 | 
			
		||||
Copyright (c) 2003-2019 University of Illinois at Urbana-Champaign.
 | 
			
		||||
All rights reserved.
 | 
			
		||||
 | 
			
		||||
Developed by:
 | 
			
		||||
 | 
			
		||||
    LLVM Team
 | 
			
		||||
 | 
			
		||||
    University of Illinois at Urbana-Champaign
 | 
			
		||||
 | 
			
		||||
    http://llvm.org
 | 
			
		||||
 | 
			
		||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
 | 
			
		||||
this software and associated documentation files (the "Software"), to deal with
 | 
			
		||||
the Software without restriction, including without limitation the rights to
 | 
			
		||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 | 
			
		||||
of the Software, and to permit persons to whom the Software is furnished to do
 | 
			
		||||
so, subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
    * Redistributions of source code must retain the above copyright notice,
 | 
			
		||||
      this list of conditions and the following disclaimers.
 | 
			
		||||
 | 
			
		||||
    * Redistributions in binary form must reproduce the above copyright notice,
 | 
			
		||||
      this list of conditions and the following disclaimers in the
 | 
			
		||||
      documentation and/or other materials provided with the distribution.
 | 
			
		||||
 | 
			
		||||
    * Neither the names of the LLVM Team, University of Illinois at
 | 
			
		||||
      Urbana-Champaign, nor the names of its contributors may be used to
 | 
			
		||||
      endorse or promote products derived from this Software without specific
 | 
			
		||||
      prior written permission.
 | 
			
		||||
 | 
			
		||||
THE SOFTWARE IS 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.  IN NO EVENT SHALL THE
 | 
			
		||||
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
 | 
			
		||||
SOFTWARE.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										127
									
								
								externals/demangle/StringView.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								externals/demangle/StringView.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,127 @@
 | 
			
		||||
//===--- StringView.h -------------------------------------------*- 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-FileCopyrightText: Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | 
			
		||||
//
 | 
			
		||||
//===----------------------------------------------------------------------===//
 | 
			
		||||
//
 | 
			
		||||
// FIXME: Use std::string_view instead when we support C++17.
 | 
			
		||||
//
 | 
			
		||||
//===----------------------------------------------------------------------===//
 | 
			
		||||
 | 
			
		||||
#ifndef DEMANGLE_STRINGVIEW_H
 | 
			
		||||
#define DEMANGLE_STRINGVIEW_H
 | 
			
		||||
 | 
			
		||||
#include "DemangleConfig.h"
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <cassert>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
 | 
			
		||||
DEMANGLE_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
class StringView {
 | 
			
		||||
  const char *First;
 | 
			
		||||
  const char *Last;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  static const size_t npos = ~size_t(0);
 | 
			
		||||
 | 
			
		||||
  template <size_t N>
 | 
			
		||||
  StringView(const char (&Str)[N]) : First(Str), Last(Str + N - 1) {}
 | 
			
		||||
  StringView(const char *First_, const char *Last_)
 | 
			
		||||
      : First(First_), Last(Last_) {}
 | 
			
		||||
  StringView(const char *First_, size_t Len)
 | 
			
		||||
      : First(First_), Last(First_ + Len) {}
 | 
			
		||||
  StringView(const char *Str) : First(Str), Last(Str + std::strlen(Str)) {}
 | 
			
		||||
  StringView() : First(nullptr), Last(nullptr) {}
 | 
			
		||||
 | 
			
		||||
  StringView substr(size_t From) const {
 | 
			
		||||
    return StringView(begin() + From, size() - From);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  size_t find(char C, size_t From = 0) const {
 | 
			
		||||
    size_t FindBegin = std::min(From, size());
 | 
			
		||||
    // Avoid calling memchr with nullptr.
 | 
			
		||||
    if (FindBegin < size()) {
 | 
			
		||||
      // Just forward to memchr, which is faster than a hand-rolled loop.
 | 
			
		||||
      if (const void *P = ::memchr(First + FindBegin, C, size() - FindBegin))
 | 
			
		||||
        return size_t(static_cast<const char *>(P) - First);
 | 
			
		||||
    }
 | 
			
		||||
    return npos;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  StringView substr(size_t From, size_t To) const {
 | 
			
		||||
    if (To >= size())
 | 
			
		||||
      To = size() - 1;
 | 
			
		||||
    if (From >= size())
 | 
			
		||||
      From = size() - 1;
 | 
			
		||||
    return StringView(First + From, First + To);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  StringView dropFront(size_t N = 1) const {
 | 
			
		||||
    if (N >= size())
 | 
			
		||||
      N = size();
 | 
			
		||||
    return StringView(First + N, Last);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  StringView dropBack(size_t N = 1) const {
 | 
			
		||||
    if (N >= size())
 | 
			
		||||
      N = size();
 | 
			
		||||
    return StringView(First, Last - N);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  char front() const {
 | 
			
		||||
    assert(!empty());
 | 
			
		||||
    return *begin();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  char back() const {
 | 
			
		||||
    assert(!empty());
 | 
			
		||||
    return *(end() - 1);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  char popFront() {
 | 
			
		||||
    assert(!empty());
 | 
			
		||||
    return *First++;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool consumeFront(char C) {
 | 
			
		||||
    if (!startsWith(C))
 | 
			
		||||
      return false;
 | 
			
		||||
    *this = dropFront(1);
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool consumeFront(StringView S) {
 | 
			
		||||
    if (!startsWith(S))
 | 
			
		||||
      return false;
 | 
			
		||||
    *this = dropFront(S.size());
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool startsWith(char C) const { return !empty() && *begin() == C; }
 | 
			
		||||
 | 
			
		||||
  bool startsWith(StringView Str) const {
 | 
			
		||||
    if (Str.size() > size())
 | 
			
		||||
      return false;
 | 
			
		||||
    return std::equal(Str.begin(), Str.end(), begin());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const char &operator[](size_t Idx) const { return *(begin() + Idx); }
 | 
			
		||||
 | 
			
		||||
  const char *begin() const { return First; }
 | 
			
		||||
  const char *end() const { return Last; }
 | 
			
		||||
  size_t size() const { return static_cast<size_t>(Last - First); }
 | 
			
		||||
  bool empty() const { return First == Last; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
inline bool operator==(const StringView &LHS, const StringView &RHS) {
 | 
			
		||||
  return LHS.size() == RHS.size() &&
 | 
			
		||||
         std::equal(LHS.begin(), LHS.end(), RHS.begin());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEMANGLE_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										192
									
								
								externals/demangle/Utility.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								externals/demangle/Utility.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,192 @@
 | 
			
		||||
//===--- Utility.h ----------------------------------------------*- 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-FileCopyrightText: Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | 
			
		||||
//
 | 
			
		||||
//===----------------------------------------------------------------------===//
 | 
			
		||||
//
 | 
			
		||||
// Provide some utility classes for use in the demangler(s).
 | 
			
		||||
//
 | 
			
		||||
//===----------------------------------------------------------------------===//
 | 
			
		||||
 | 
			
		||||
#ifndef DEMANGLE_UTILITY_H
 | 
			
		||||
#define DEMANGLE_UTILITY_H
 | 
			
		||||
 | 
			
		||||
#include "StringView.h"
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstdlib>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <iterator>
 | 
			
		||||
#include <limits>
 | 
			
		||||
 | 
			
		||||
DEMANGLE_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
// Stream that AST nodes write their string representation into after the AST
 | 
			
		||||
// has been parsed.
 | 
			
		||||
class OutputStream {
 | 
			
		||||
  char *Buffer;
 | 
			
		||||
  size_t CurrentPosition;
 | 
			
		||||
  size_t BufferCapacity;
 | 
			
		||||
 | 
			
		||||
  // Ensure there is at least n more positions in buffer.
 | 
			
		||||
  void grow(size_t N) {
 | 
			
		||||
    if (N + CurrentPosition >= BufferCapacity) {
 | 
			
		||||
      BufferCapacity *= 2;
 | 
			
		||||
      if (BufferCapacity < N + CurrentPosition)
 | 
			
		||||
        BufferCapacity = N + CurrentPosition;
 | 
			
		||||
      Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));
 | 
			
		||||
      if (Buffer == nullptr)
 | 
			
		||||
        std::terminate();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void writeUnsigned(uint64_t N, bool isNeg = false) {
 | 
			
		||||
    // Handle special case...
 | 
			
		||||
    if (N == 0) {
 | 
			
		||||
      *this << '0';
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    char Temp[21];
 | 
			
		||||
    char *TempPtr = std::end(Temp);
 | 
			
		||||
 | 
			
		||||
    while (N) {
 | 
			
		||||
      *--TempPtr = '0' + char(N % 10);
 | 
			
		||||
      N /= 10;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Add negative sign...
 | 
			
		||||
    if (isNeg)
 | 
			
		||||
      *--TempPtr = '-';
 | 
			
		||||
    this->operator<<(StringView(TempPtr, std::end(Temp)));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  OutputStream(char *StartBuf, size_t Size)
 | 
			
		||||
      : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {}
 | 
			
		||||
  OutputStream() = default;
 | 
			
		||||
  void reset(char *Buffer_, size_t BufferCapacity_) {
 | 
			
		||||
    CurrentPosition = 0;
 | 
			
		||||
    Buffer = Buffer_;
 | 
			
		||||
    BufferCapacity = BufferCapacity_;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// If a ParameterPackExpansion (or similar type) is encountered, the offset
 | 
			
		||||
  /// into the pack that we're currently printing.
 | 
			
		||||
  unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
 | 
			
		||||
  unsigned CurrentPackMax = std::numeric_limits<unsigned>::max();
 | 
			
		||||
 | 
			
		||||
  OutputStream &operator+=(StringView R) {
 | 
			
		||||
    size_t Size = R.size();
 | 
			
		||||
    if (Size == 0)
 | 
			
		||||
      return *this;
 | 
			
		||||
    grow(Size);
 | 
			
		||||
    std::memmove(Buffer + CurrentPosition, R.begin(), Size);
 | 
			
		||||
    CurrentPosition += Size;
 | 
			
		||||
    return *this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  OutputStream &operator+=(char C) {
 | 
			
		||||
    grow(1);
 | 
			
		||||
    Buffer[CurrentPosition++] = C;
 | 
			
		||||
    return *this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  OutputStream &operator<<(StringView R) { return (*this += R); }
 | 
			
		||||
 | 
			
		||||
  OutputStream &operator<<(char C) { return (*this += C); }
 | 
			
		||||
 | 
			
		||||
  OutputStream &operator<<(long long N) {
 | 
			
		||||
    if (N < 0)
 | 
			
		||||
      writeUnsigned(static_cast<unsigned long long>(-N), true);
 | 
			
		||||
    else
 | 
			
		||||
      writeUnsigned(static_cast<unsigned long long>(N));
 | 
			
		||||
    return *this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  OutputStream &operator<<(unsigned long long N) {
 | 
			
		||||
    writeUnsigned(N, false);
 | 
			
		||||
    return *this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  OutputStream &operator<<(long N) {
 | 
			
		||||
    return this->operator<<(static_cast<long long>(N));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  OutputStream &operator<<(unsigned long N) {
 | 
			
		||||
    return this->operator<<(static_cast<unsigned long long>(N));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  OutputStream &operator<<(int N) {
 | 
			
		||||
    return this->operator<<(static_cast<long long>(N));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  OutputStream &operator<<(unsigned int N) {
 | 
			
		||||
    return this->operator<<(static_cast<unsigned long long>(N));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  size_t getCurrentPosition() const { return CurrentPosition; }
 | 
			
		||||
  void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
 | 
			
		||||
 | 
			
		||||
  char back() const {
 | 
			
		||||
    return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool empty() const { return CurrentPosition == 0; }
 | 
			
		||||
 | 
			
		||||
  char *getBuffer() { return Buffer; }
 | 
			
		||||
  char *getBufferEnd() { return Buffer + CurrentPosition - 1; }
 | 
			
		||||
  size_t getBufferCapacity() { return BufferCapacity; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <class T> class SwapAndRestore {
 | 
			
		||||
  T &Restore;
 | 
			
		||||
  T OriginalValue;
 | 
			
		||||
  bool ShouldRestore = true;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  SwapAndRestore(T &Restore_) : SwapAndRestore(Restore_, Restore_) {}
 | 
			
		||||
 | 
			
		||||
  SwapAndRestore(T &Restore_, T NewVal)
 | 
			
		||||
      : Restore(Restore_), OriginalValue(Restore) {
 | 
			
		||||
    Restore = std::move(NewVal);
 | 
			
		||||
  }
 | 
			
		||||
  ~SwapAndRestore() {
 | 
			
		||||
    if (ShouldRestore)
 | 
			
		||||
      Restore = std::move(OriginalValue);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void shouldRestore(bool ShouldRestore_) { ShouldRestore = ShouldRestore_; }
 | 
			
		||||
 | 
			
		||||
  void restoreNow(bool Force) {
 | 
			
		||||
    if (!Force && !ShouldRestore)
 | 
			
		||||
      return;
 | 
			
		||||
 | 
			
		||||
    Restore = std::move(OriginalValue);
 | 
			
		||||
    ShouldRestore = false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  SwapAndRestore(const SwapAndRestore &) = delete;
 | 
			
		||||
  SwapAndRestore &operator=(const SwapAndRestore &) = delete;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
inline bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S,
 | 
			
		||||
                                   size_t InitSize) {
 | 
			
		||||
  size_t BufferSize;
 | 
			
		||||
  if (Buf == nullptr) {
 | 
			
		||||
    Buf = static_cast<char *>(std::malloc(InitSize));
 | 
			
		||||
    if (Buf == nullptr)
 | 
			
		||||
      return false;
 | 
			
		||||
    BufferSize = InitSize;
 | 
			
		||||
  } else
 | 
			
		||||
    BufferSize = *N;
 | 
			
		||||
 | 
			
		||||
  S.reset(Buf, BufferSize);
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEMANGLE_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
		Reference in New Issue
	
	Block a user