244 lines · c
1//===--- Utility.h ----------------------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Provide some utility classes for use in the demangler.10// There are two copies of this file in the source tree. The one in libcxxabi11// is the original and the one in llvm is the copy. Use cp-to-llvm.sh to update12// the copy. See README.txt for more details.13//14//===----------------------------------------------------------------------===//15 16#ifndef DEMANGLE_UTILITY_H17#define DEMANGLE_UTILITY_H18 19#include "DemangleConfig.h"20 21#include <array>22#include <cstdint>23#include <cstdlib>24#include <cstring>25#include <limits>26#include <string_view>27 28DEMANGLE_NAMESPACE_BEGIN29 30class Node;31 32// Stream that AST nodes write their string representation into after the AST33// has been parsed.34class OutputBuffer {35 char *Buffer = nullptr;36 size_t CurrentPosition = 0;37 size_t BufferCapacity = 0;38 39 // Ensure there are at least N more positions in the buffer.40 void grow(size_t N) {41 size_t Need = N + CurrentPosition;42 if (Need > BufferCapacity) {43 // Reduce the number of reallocations, with a bit of hysteresis. The44 // number here is chosen so the first allocation will more-than-likely not45 // allocate more than 1K.46 Need += 1024 - 32;47 BufferCapacity *= 2;48 if (BufferCapacity < Need)49 BufferCapacity = Need;50 Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));51 if (Buffer == nullptr)52 std::abort();53 }54 }55 56 OutputBuffer &writeUnsigned(uint64_t N, bool isNeg = false) {57 std::array<char, 21> Temp;58 char *TempPtr = Temp.data() + Temp.size();59 60 // Output at least one character.61 do {62 *--TempPtr = char('0' + N % 10);63 N /= 10;64 } while (N);65 66 // Add negative sign.67 if (isNeg)68 *--TempPtr = '-';69 70 return operator+=(71 std::string_view(TempPtr, Temp.data() + Temp.size() - TempPtr));72 }73 74public:75 OutputBuffer(char *StartBuf, size_t Size)76 : Buffer(StartBuf), BufferCapacity(Size) {}77 OutputBuffer(char *StartBuf, size_t *SizePtr)78 : OutputBuffer(StartBuf, StartBuf ? *SizePtr : 0) {}79 OutputBuffer() = default;80 // Non-copyable81 OutputBuffer(const OutputBuffer &) = delete;82 OutputBuffer &operator=(const OutputBuffer &) = delete;83 84 virtual ~OutputBuffer() = default;85 86 operator std::string_view() const {87 return std::string_view(Buffer, CurrentPosition);88 }89 90 /// Called by the demangler when printing the demangle tree. By91 /// default calls into \c Node::print{Left|Right} but can be overriden92 /// by clients to track additional state when printing the demangled name.93 virtual void printLeft(const Node &N);94 virtual void printRight(const Node &N);95 96 /// Called when we write to this object anywhere other than the end.97 virtual void notifyInsertion(size_t /*Position*/, size_t /*Count*/) {}98 99 /// Called when we make the \c CurrentPosition of this object smaller.100 virtual void notifyDeletion(size_t /*OldPos*/, size_t /*NewPos*/) {}101 102 /// If a ParameterPackExpansion (or similar type) is encountered, the offset103 /// into the pack that we're currently printing.104 unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();105 unsigned CurrentPackMax = std::numeric_limits<unsigned>::max();106 107 struct {108 /// The depth of '(' and ')' inside the currently printed template109 /// arguments.110 unsigned ParenDepth = 0;111 112 /// True if we're currently printing a template argument.113 bool InsideTemplate = false;114 } TemplateTracker;115 116 /// Returns true if we're currently between a '(' and ')' when printing117 /// template args.118 bool isInParensInTemplateArgs() const {119 return TemplateTracker.ParenDepth > 0;120 }121 122 /// Returns true if we're printing template args.123 bool isInsideTemplateArgs() const { return TemplateTracker.InsideTemplate; }124 125 void printOpen(char Open = '(') {126 if (isInsideTemplateArgs())127 TemplateTracker.ParenDepth++;128 *this += Open;129 }130 void printClose(char Close = ')') {131 if (isInsideTemplateArgs())132 TemplateTracker.ParenDepth--;133 *this += Close;134 }135 136 OutputBuffer &operator+=(std::string_view R) {137 if (size_t Size = R.size()) {138 grow(Size);139 std::memcpy(Buffer + CurrentPosition, &*R.begin(), Size);140 CurrentPosition += Size;141 }142 return *this;143 }144 145 OutputBuffer &operator+=(char C) {146 grow(1);147 Buffer[CurrentPosition++] = C;148 return *this;149 }150 151 OutputBuffer &prepend(std::string_view R) {152 size_t Size = R.size();153 if (!Size)154 return *this;155 156 grow(Size);157 std::memmove(Buffer + Size, Buffer, CurrentPosition);158 std::memcpy(Buffer, &*R.begin(), Size);159 CurrentPosition += Size;160 161 notifyInsertion(/*Position=*/0, /*Count=*/Size);162 163 return *this;164 }165 166 OutputBuffer &operator<<(std::string_view R) { return (*this += R); }167 168 OutputBuffer &operator<<(char C) { return (*this += C); }169 170 OutputBuffer &operator<<(long long N) {171 return writeUnsigned(static_cast<unsigned long long>(std::abs(N)), N < 0);172 }173 174 OutputBuffer &operator<<(unsigned long long N) {175 return writeUnsigned(N, false);176 }177 178 OutputBuffer &operator<<(long N) {179 return this->operator<<(static_cast<long long>(N));180 }181 182 OutputBuffer &operator<<(unsigned long N) {183 return this->operator<<(static_cast<unsigned long long>(N));184 }185 186 OutputBuffer &operator<<(int N) {187 return this->operator<<(static_cast<long long>(N));188 }189 190 OutputBuffer &operator<<(unsigned int N) {191 return this->operator<<(static_cast<unsigned long long>(N));192 }193 194 void insert(size_t Pos, const char *S, size_t N) {195 DEMANGLE_ASSERT(Pos <= CurrentPosition, "");196 if (N == 0)197 return;198 199 grow(N);200 std::memmove(Buffer + Pos + N, Buffer + Pos, CurrentPosition - Pos);201 std::memcpy(Buffer + Pos, S, N);202 CurrentPosition += N;203 204 notifyInsertion(Pos, N);205 }206 207 size_t getCurrentPosition() const { return CurrentPosition; }208 void setCurrentPosition(size_t NewPos) {209 notifyDeletion(CurrentPosition, NewPos);210 CurrentPosition = NewPos;211 }212 213 char back() const {214 DEMANGLE_ASSERT(CurrentPosition, "");215 return Buffer[CurrentPosition - 1];216 }217 218 bool empty() const { return CurrentPosition == 0; }219 220 char *getBuffer() { return Buffer; }221 char *getBufferEnd() { return Buffer + CurrentPosition - 1; }222 size_t getBufferCapacity() const { return BufferCapacity; }223};224 225template <class T> class ScopedOverride {226 T &Loc;227 T Original;228 229public:230 ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {}231 232 ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) {233 Loc_ = std::move(NewVal);234 }235 ~ScopedOverride() { Loc = std::move(Original); }236 237 ScopedOverride(const ScopedOverride &) = delete;238 ScopedOverride &operator=(const ScopedOverride &) = delete;239};240 241DEMANGLE_NAMESPACE_END242 243#endif244