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 "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 is at least n more positions in buffer. 37 void grow(size_t N) { 38 if (N + CurrentPosition >= BufferCapacity) { 39 BufferCapacity *= 2; 40 if (BufferCapacity < N + CurrentPosition) 41 BufferCapacity = N + CurrentPosition; 42 Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity)); 43 if (Buffer == nullptr) 44 std::terminate(); 45 } 46 } 47 48 void writeUnsigned(uint64_t N, bool isNeg = false) { 49 // Handle special case... 50 if (N == 0) { 51 *this << '0'; 52 return; 53 } 54 55 std::array<char, 21> Temp; 56 char *TempPtr = Temp.data() + Temp.size(); 57 58 while (N) { 59 *--TempPtr = char('0' + N % 10); 60 N /= 10; 61 } 62 63 // Add negative sign... 64 if (isNeg) 65 *--TempPtr = '-'; 66 this->operator<<(StringView(TempPtr, Temp.data() + Temp.size())); 67 } 68 69 public: 70 OutputBuffer(char *StartBuf, size_t Size) 71 : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {} 72 OutputBuffer() = default; 73 void reset(char *Buffer_, size_t BufferCapacity_) { 74 CurrentPosition = 0; 75 Buffer = Buffer_; 76 BufferCapacity = BufferCapacity_; 77 } 78 79 /// If a ParameterPackExpansion (or similar type) is encountered, the offset 80 /// into the pack that we're currently printing. 81 unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max(); 82 unsigned CurrentPackMax = std::numeric_limits<unsigned>::max(); 83 84 OutputBuffer &operator+=(StringView R) { 85 size_t Size = R.size(); 86 if (Size == 0) 87 return *this; 88 grow(Size); 89 std::memmove(Buffer + CurrentPosition, R.begin(), Size); 90 CurrentPosition += Size; 91 return *this; 92 } 93 94 OutputBuffer &operator+=(char C) { 95 grow(1); 96 Buffer[CurrentPosition++] = C; 97 return *this; 98 } 99 100 OutputBuffer &operator<<(StringView R) { return (*this += R); } 101 102 OutputBuffer prepend(StringView R) { 103 size_t Size = R.size(); 104 105 grow(Size); 106 std::memmove(Buffer + Size, Buffer, CurrentPosition); 107 std::memcpy(Buffer, R.begin(), Size); 108 CurrentPosition += Size; 109 110 return *this; 111 } 112 113 OutputBuffer &operator<<(char C) { return (*this += C); } 114 115 OutputBuffer &operator<<(long long N) { 116 if (N < 0) 117 writeUnsigned(static_cast<unsigned long long>(-N), true); 118 else 119 writeUnsigned(static_cast<unsigned long long>(N)); 120 return *this; 121 } 122 123 OutputBuffer &operator<<(unsigned long long N) { 124 writeUnsigned(N, false); 125 return *this; 126 } 127 128 OutputBuffer &operator<<(long N) { 129 return this->operator<<(static_cast<long long>(N)); 130 } 131 132 OutputBuffer &operator<<(unsigned long N) { 133 return this->operator<<(static_cast<unsigned long long>(N)); 134 } 135 136 OutputBuffer &operator<<(int N) { 137 return this->operator<<(static_cast<long long>(N)); 138 } 139 140 OutputBuffer &operator<<(unsigned int N) { 141 return this->operator<<(static_cast<unsigned long long>(N)); 142 } 143 144 void insert(size_t Pos, const char *S, size_t N) { 145 assert(Pos <= CurrentPosition); 146 if (N == 0) 147 return; 148 grow(N); 149 std::memmove(Buffer + Pos + N, Buffer + Pos, CurrentPosition - Pos); 150 std::memcpy(Buffer + Pos, S, N); 151 CurrentPosition += N; 152 } 153 154 size_t getCurrentPosition() const { return CurrentPosition; } 155 void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; } 156 157 char back() const { 158 return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0'; 159 } 160 161 bool empty() const { return CurrentPosition == 0; } 162 163 char *getBuffer() { return Buffer; } 164 char *getBufferEnd() { return Buffer + CurrentPosition - 1; } 165 size_t getBufferCapacity() const { return BufferCapacity; } 166 }; 167 168 template <class T> class SwapAndRestore { 169 T &Restore; 170 T OriginalValue; 171 bool ShouldRestore = true; 172 173 public: 174 SwapAndRestore(T &Restore_) : SwapAndRestore(Restore_, Restore_) {} 175 176 SwapAndRestore(T &Restore_, T NewVal) 177 : Restore(Restore_), OriginalValue(Restore) { 178 Restore = std::move(NewVal); 179 } 180 ~SwapAndRestore() { 181 if (ShouldRestore) 182 Restore = std::move(OriginalValue); 183 } 184 185 void shouldRestore(bool ShouldRestore_) { ShouldRestore = ShouldRestore_; } 186 187 void restoreNow(bool Force) { 188 if (!Force && !ShouldRestore) 189 return; 190 191 Restore = std::move(OriginalValue); 192 ShouldRestore = false; 193 } 194 195 SwapAndRestore(const SwapAndRestore &) = delete; 196 SwapAndRestore &operator=(const SwapAndRestore &) = delete; 197 }; 198 199 inline bool initializeOutputBuffer(char *Buf, size_t *N, OutputBuffer &OB, 200 size_t InitSize) { 201 size_t BufferSize; 202 if (Buf == nullptr) { 203 Buf = static_cast<char *>(std::malloc(InitSize)); 204 if (Buf == nullptr) 205 return false; 206 BufferSize = InitSize; 207 } else 208 BufferSize = *N; 209 210 OB.reset(Buf, BufferSize); 211 return true; 212 } 213 214 DEMANGLE_NAMESPACE_END 215 216 #endif 217