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