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 DEMANGLE_UTILITY_H 14 #define 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 OutputStream { 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 = '0' + char(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 OutputStream(char *StartBuf, size_t Size) 67 : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {} 68 OutputStream() = 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 OutputStream &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 OutputStream &operator+=(char C) { 91 grow(1); 92 Buffer[CurrentPosition++] = C; 93 return *this; 94 } 95 96 OutputStream &operator<<(StringView R) { return (*this += R); } 97 98 OutputStream &operator<<(char C) { return (*this += C); } 99 100 OutputStream &operator<<(long long N) { 101 if (N < 0) 102 writeUnsigned(static_cast<unsigned long long>(-N), true); 103 else 104 writeUnsigned(static_cast<unsigned long long>(N)); 105 return *this; 106 } 107 108 OutputStream &operator<<(unsigned long long N) { 109 writeUnsigned(N, false); 110 return *this; 111 } 112 113 OutputStream &operator<<(long N) { 114 return this->operator<<(static_cast<long long>(N)); 115 } 116 117 OutputStream &operator<<(unsigned long N) { 118 return this->operator<<(static_cast<unsigned long long>(N)); 119 } 120 121 OutputStream &operator<<(int N) { 122 return this->operator<<(static_cast<long long>(N)); 123 } 124 125 OutputStream &operator<<(unsigned int N) { 126 return this->operator<<(static_cast<unsigned long long>(N)); 127 } 128 129 size_t getCurrentPosition() const { return CurrentPosition; } 130 void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; } 131 132 char back() const { 133 return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0'; 134 } 135 136 bool empty() const { return CurrentPosition == 0; } 137 138 char *getBuffer() { return Buffer; } 139 char *getBufferEnd() { return Buffer + CurrentPosition - 1; } 140 size_t getBufferCapacity() const { return BufferCapacity; } 141 }; 142 143 template <class T> class SwapAndRestore { 144 T &Restore; 145 T OriginalValue; 146 bool ShouldRestore = true; 147 148 public: 149 SwapAndRestore(T &Restore_) : SwapAndRestore(Restore_, Restore_) {} 150 151 SwapAndRestore(T &Restore_, T NewVal) 152 : Restore(Restore_), OriginalValue(Restore) { 153 Restore = std::move(NewVal); 154 } 155 ~SwapAndRestore() { 156 if (ShouldRestore) 157 Restore = std::move(OriginalValue); 158 } 159 160 void shouldRestore(bool ShouldRestore_) { ShouldRestore = ShouldRestore_; } 161 162 void restoreNow(bool Force) { 163 if (!Force && !ShouldRestore) 164 return; 165 166 Restore = std::move(OriginalValue); 167 ShouldRestore = false; 168 } 169 170 SwapAndRestore(const SwapAndRestore &) = delete; 171 SwapAndRestore &operator=(const SwapAndRestore &) = delete; 172 }; 173 174 inline bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S, 175 size_t InitSize) { 176 size_t BufferSize; 177 if (Buf == nullptr) { 178 Buf = static_cast<char *>(std::malloc(InitSize)); 179 if (Buf == nullptr) 180 return false; 181 BufferSize = InitSize; 182 } else 183 BufferSize = *N; 184 185 S.reset(Buf, BufferSize); 186 return true; 187 } 188 189 DEMANGLE_NAMESPACE_END 190 191 #endif 192