1 //===--- Utility.h -------------------*- mode:c++;eval:(read-only-mode) -*-===// 2 // Do not edit! See README.txt. 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-exception 6 // 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 libcxxabi 11 // is the original and the one in llvm is the copy. Use cp-to-llvm.sh to update 12 // the copy. See README.txt for more details. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #ifndef DEMANGLE_UTILITY_H 17 #define DEMANGLE_UTILITY_H 18 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 28 DEMANGLE_NAMESPACE_BEGIN 29 30 class Node; 31 32 // Stream that AST nodes write their string representation into after the AST 33 // has been parsed. 34 class 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. grow(size_t N)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. The 44 // number here is chosen so the first allocation will more-than-likely not 45 // 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 74 public: OutputBuffer(char * StartBuf,size_t Size)75 OutputBuffer(char *StartBuf, size_t Size) 76 : Buffer(StartBuf), BufferCapacity(Size) {} OutputBuffer(char * StartBuf,size_t * SizePtr)77 OutputBuffer(char *StartBuf, size_t *SizePtr) 78 : OutputBuffer(StartBuf, StartBuf ? *SizePtr : 0) {} 79 OutputBuffer() = default; 80 // Non-copyable 81 OutputBuffer(const OutputBuffer &) = delete; 82 OutputBuffer &operator=(const OutputBuffer &) = delete; 83 ~OutputBuffer()84 virtual ~OutputBuffer() {} 85 string_view()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. By 91 /// default calls into \c Node::print{Left|Right} but can be overriden 92 /// 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. notifyInsertion(size_t,size_t)97 virtual void notifyInsertion(size_t /*Position*/, size_t /*Count*/) {} 98 99 /// Called when we make the \c CurrentPosition of this object smaller. notifyDeletion(size_t,size_t)100 virtual void notifyDeletion(size_t /*OldPos*/, size_t /*NewPos*/) {} 101 102 /// If a ParameterPackExpansion (or similar type) is encountered, the offset 103 /// 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 /// When zero, we're printing template args and '>' needs to be parenthesized. 108 /// Use a counter so we can simply increment inside parentheses. 109 unsigned GtIsGt = 1; 110 isGtInsideTemplateArgs()111 bool isGtInsideTemplateArgs() const { return GtIsGt == 0; } 112 113 void printOpen(char Open = '(') { 114 GtIsGt++; 115 *this += Open; 116 } 117 void printClose(char Close = ')') { 118 GtIsGt--; 119 *this += Close; 120 } 121 122 OutputBuffer &operator+=(std::string_view R) { 123 if (size_t Size = R.size()) { 124 grow(Size); 125 std::memcpy(Buffer + CurrentPosition, &*R.begin(), Size); 126 CurrentPosition += Size; 127 } 128 return *this; 129 } 130 131 OutputBuffer &operator+=(char C) { 132 grow(1); 133 Buffer[CurrentPosition++] = C; 134 return *this; 135 } 136 prepend(std::string_view R)137 OutputBuffer &prepend(std::string_view R) { 138 size_t Size = R.size(); 139 if (!Size) 140 return *this; 141 142 grow(Size); 143 std::memmove(Buffer + Size, Buffer, CurrentPosition); 144 std::memcpy(Buffer, &*R.begin(), Size); 145 CurrentPosition += Size; 146 147 notifyInsertion(/*Position=*/0, /*Count=*/Size); 148 149 return *this; 150 } 151 152 OutputBuffer &operator<<(std::string_view R) { return (*this += R); } 153 154 OutputBuffer &operator<<(char C) { return (*this += C); } 155 156 OutputBuffer &operator<<(long long N) { 157 return writeUnsigned(static_cast<unsigned long long>(std::abs(N)), N < 0); 158 } 159 160 OutputBuffer &operator<<(unsigned long long N) { 161 return writeUnsigned(N, false); 162 } 163 164 OutputBuffer &operator<<(long N) { 165 return this->operator<<(static_cast<long long>(N)); 166 } 167 168 OutputBuffer &operator<<(unsigned long N) { 169 return this->operator<<(static_cast<unsigned long long>(N)); 170 } 171 172 OutputBuffer &operator<<(int N) { 173 return this->operator<<(static_cast<long long>(N)); 174 } 175 176 OutputBuffer &operator<<(unsigned int N) { 177 return this->operator<<(static_cast<unsigned long long>(N)); 178 } 179 insert(size_t Pos,const char * S,size_t N)180 void insert(size_t Pos, const char *S, size_t N) { 181 DEMANGLE_ASSERT(Pos <= CurrentPosition, ""); 182 if (N == 0) 183 return; 184 185 grow(N); 186 std::memmove(Buffer + Pos + N, Buffer + Pos, CurrentPosition - Pos); 187 std::memcpy(Buffer + Pos, S, N); 188 CurrentPosition += N; 189 190 notifyInsertion(Pos, N); 191 } 192 getCurrentPosition()193 size_t getCurrentPosition() const { return CurrentPosition; } setCurrentPosition(size_t NewPos)194 void setCurrentPosition(size_t NewPos) { 195 notifyDeletion(CurrentPosition, NewPos); 196 CurrentPosition = NewPos; 197 } 198 back()199 char back() const { 200 DEMANGLE_ASSERT(CurrentPosition, ""); 201 return Buffer[CurrentPosition - 1]; 202 } 203 empty()204 bool empty() const { return CurrentPosition == 0; } 205 getBuffer()206 char *getBuffer() { return Buffer; } getBufferEnd()207 char *getBufferEnd() { return Buffer + CurrentPosition - 1; } getBufferCapacity()208 size_t getBufferCapacity() const { return BufferCapacity; } 209 }; 210 211 template <class T> class ScopedOverride { 212 T &Loc; 213 T Original; 214 215 public: ScopedOverride(T & Loc_)216 ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {} 217 ScopedOverride(T & Loc_,T NewVal)218 ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) { 219 Loc_ = std::move(NewVal); 220 } ~ScopedOverride()221 ~ScopedOverride() { Loc = std::move(Original); } 222 223 ScopedOverride(const ScopedOverride &) = delete; 224 ScopedOverride &operator=(const ScopedOverride &) = delete; 225 }; 226 227 DEMANGLE_NAMESPACE_END 228 229 #endif 230