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 LLVM_DEMANGLE_UTILITY_H 17 #define LLVM_DEMANGLE_UTILITY_H 18 19 #include "StringView.h" 20 #include <array> 21 #include <cstdint> 22 #include <cstdlib> 23 #include <cstring> 24 #include <exception> 25 #include <limits> 26 27 DEMANGLE_NAMESPACE_BEGIN 28 29 // Stream that AST nodes write their string representation into after the AST 30 // has been parsed. 31 class OutputBuffer { 32 char *Buffer = nullptr; 33 size_t CurrentPosition = 0; 34 size_t BufferCapacity = 0; 35 36 // Ensure there are at least N more positions in the buffer. 37 void grow(size_t N) { 38 size_t Need = N + CurrentPosition; 39 if (Need > BufferCapacity) { 40 // Reduce the number of reallocations, with a bit of hysteresis. The 41 // number here is chosen so the first allocation will more-than-likely not 42 // allocate more than 1K. 43 Need += 1024 - 32; 44 BufferCapacity *= 2; 45 if (BufferCapacity < Need) 46 BufferCapacity = Need; 47 Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity)); 48 if (Buffer == nullptr) 49 std::terminate(); 50 } 51 } 52 53 OutputBuffer &writeUnsigned(uint64_t N, bool isNeg = false) { 54 std::array<char, 21> Temp; 55 char *TempPtr = Temp.data() + Temp.size(); 56 57 // Output at least one character. 58 do { 59 *--TempPtr = char('0' + N % 10); 60 N /= 10; 61 } while (N); 62 63 // Add negative sign. 64 if (isNeg) 65 *--TempPtr = '-'; 66 67 return operator+=(StringView(TempPtr, Temp.data() + Temp.size())); 68 } 69 70 public: 71 OutputBuffer(char *StartBuf, size_t Size) 72 : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {} 73 OutputBuffer() = default; 74 // Non-copyable 75 OutputBuffer(const OutputBuffer &) = delete; 76 OutputBuffer &operator=(const OutputBuffer &) = delete; 77 78 operator StringView() const { return StringView(Buffer, CurrentPosition); } 79 80 void reset(char *Buffer_, size_t BufferCapacity_) { 81 CurrentPosition = 0; 82 Buffer = Buffer_; 83 BufferCapacity = BufferCapacity_; 84 } 85 86 /// If a ParameterPackExpansion (or similar type) is encountered, the offset 87 /// into the pack that we're currently printing. 88 unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max(); 89 unsigned CurrentPackMax = std::numeric_limits<unsigned>::max(); 90 91 /// When zero, we're printing template args and '>' needs to be parenthesized. 92 /// Use a counter so we can simply increment inside parentheses. 93 unsigned GtIsGt = 1; 94 95 bool isGtInsideTemplateArgs() const { return GtIsGt == 0; } 96 97 void printOpen(char Open = '(') { 98 GtIsGt++; 99 *this += Open; 100 } 101 void printClose(char Close = ')') { 102 GtIsGt--; 103 *this += Close; 104 } 105 106 OutputBuffer &operator+=(StringView R) { 107 if (size_t Size = R.size()) { 108 grow(Size); 109 std::memcpy(Buffer + CurrentPosition, R.begin(), Size); 110 CurrentPosition += Size; 111 } 112 return *this; 113 } 114 115 OutputBuffer &operator+=(char C) { 116 grow(1); 117 Buffer[CurrentPosition++] = C; 118 return *this; 119 } 120 121 OutputBuffer &prepend(StringView R) { 122 size_t Size = R.size(); 123 124 grow(Size); 125 std::memmove(Buffer + Size, Buffer, CurrentPosition); 126 std::memcpy(Buffer, R.begin(), Size); 127 CurrentPosition += Size; 128 129 return *this; 130 } 131 132 OutputBuffer &operator<<(StringView R) { return (*this += R); } 133 134 OutputBuffer &operator<<(char C) { return (*this += C); } 135 136 OutputBuffer &operator<<(long long N) { 137 return writeUnsigned(static_cast<unsigned long long>(std::abs(N)), N < 0); 138 } 139 140 OutputBuffer &operator<<(unsigned long long N) { 141 return writeUnsigned(N, false); 142 } 143 144 OutputBuffer &operator<<(long N) { 145 return this->operator<<(static_cast<long long>(N)); 146 } 147 148 OutputBuffer &operator<<(unsigned long N) { 149 return this->operator<<(static_cast<unsigned long long>(N)); 150 } 151 152 OutputBuffer &operator<<(int N) { 153 return this->operator<<(static_cast<long long>(N)); 154 } 155 156 OutputBuffer &operator<<(unsigned int N) { 157 return this->operator<<(static_cast<unsigned long long>(N)); 158 } 159 160 void insert(size_t Pos, const char *S, size_t N) { 161 assert(Pos <= CurrentPosition); 162 if (N == 0) 163 return; 164 grow(N); 165 std::memmove(Buffer + Pos + N, Buffer + Pos, CurrentPosition - Pos); 166 std::memcpy(Buffer + Pos, S, N); 167 CurrentPosition += N; 168 } 169 170 size_t getCurrentPosition() const { return CurrentPosition; } 171 void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; } 172 173 char back() const { 174 assert(CurrentPosition); 175 return Buffer[CurrentPosition - 1]; 176 } 177 178 bool empty() const { return CurrentPosition == 0; } 179 180 char *getBuffer() { return Buffer; } 181 char *getBufferEnd() { return Buffer + CurrentPosition - 1; } 182 size_t getBufferCapacity() const { return BufferCapacity; } 183 }; 184 185 template <class T> class ScopedOverride { 186 T &Loc; 187 T Original; 188 189 public: 190 ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {} 191 192 ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) { 193 Loc_ = std::move(NewVal); 194 } 195 ~ScopedOverride() { Loc = std::move(Original); } 196 197 ScopedOverride(const ScopedOverride &) = delete; 198 ScopedOverride &operator=(const ScopedOverride &) = delete; 199 }; 200 201 inline bool initializeOutputBuffer(char *Buf, size_t *N, OutputBuffer &OB, 202 size_t InitSize) { 203 size_t BufferSize; 204 if (Buf == nullptr) { 205 Buf = static_cast<char *>(std::malloc(InitSize)); 206 if (Buf == nullptr) 207 return false; 208 BufferSize = InitSize; 209 } else 210 BufferSize = *N; 211 212 OB.reset(Buf, BufferSize); 213 return true; 214 } 215 216 DEMANGLE_NAMESPACE_END 217 218 #endif 219