1 //===--- Utility.h ----------------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 // 9 // This file contains several utility classes used by the demangle library. 10 //===----------------------------------------------------------------------===// 11 12 #ifndef LLVM_DEMANGLE_UTILITY_H 13 #define LLVM_DEMANGLE_UTILITY_H 14 15 #include "StringView.h" 16 17 #include <cstdint> 18 #include <cstdlib> 19 #include <cstring> 20 #include <iterator> 21 #include <limits> 22 23 // Stream that AST nodes write their string representation into after the AST 24 // has been parsed. 25 class OutputStream { 26 char *Buffer; 27 size_t CurrentPosition; 28 size_t BufferCapacity; 29 30 // Ensure there is at least n more positions in buffer. grow(size_t N)31 void grow(size_t N) { 32 if (N + CurrentPosition >= BufferCapacity) { 33 BufferCapacity *= 2; 34 if (BufferCapacity < N + CurrentPosition) 35 BufferCapacity = N + CurrentPosition; 36 Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity)); 37 if (Buffer == nullptr) 38 std::terminate(); 39 } 40 } 41 42 void writeUnsigned(uint64_t N, bool isNeg = false) { 43 // Handle special case... 44 if (N == 0) { 45 *this << '0'; 46 return; 47 } 48 49 char Temp[21]; 50 char *TempPtr = std::end(Temp); 51 52 while (N) { 53 *--TempPtr = '0' + char(N % 10); 54 N /= 10; 55 } 56 57 // Add negative sign... 58 if (isNeg) 59 *--TempPtr = '-'; 60 this->operator<<(StringView(TempPtr, std::end(Temp))); 61 } 62 63 public: OutputStream(char * StartBuf,size_t Size)64 OutputStream(char *StartBuf, size_t Size) 65 : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {} 66 OutputStream() = default; reset(char * Buffer_,size_t BufferCapacity_)67 void reset(char *Buffer_, size_t BufferCapacity_) { 68 CurrentPosition = 0; 69 Buffer = Buffer_; 70 BufferCapacity = BufferCapacity_; 71 } 72 73 /// Create an OutputStream from a buffer and a size. If either of these are 74 /// null a buffer is allocated. create(char * StartBuf,size_t * Size,size_t AllocSize)75 static OutputStream create(char *StartBuf, size_t *Size, size_t AllocSize) { 76 OutputStream Result; 77 78 if (!StartBuf || !Size) { 79 StartBuf = static_cast<char *>(std::malloc(AllocSize)); 80 if (StartBuf == nullptr) 81 std::terminate(); 82 Size = &AllocSize; 83 } 84 85 Result.reset(StartBuf, *Size); 86 return Result; 87 } 88 89 /// If a ParameterPackExpansion (or similar type) is encountered, the offset 90 /// into the pack that we're currently printing. 91 unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max(); 92 unsigned CurrentPackMax = std::numeric_limits<unsigned>::max(); 93 94 OutputStream &operator+=(StringView R) { 95 size_t Size = R.size(); 96 if (Size == 0) 97 return *this; 98 grow(Size); 99 std::memmove(Buffer + CurrentPosition, R.begin(), Size); 100 CurrentPosition += Size; 101 return *this; 102 } 103 104 OutputStream &operator+=(char C) { 105 grow(1); 106 Buffer[CurrentPosition++] = C; 107 return *this; 108 } 109 110 OutputStream &operator<<(StringView R) { return (*this += R); } 111 112 OutputStream &operator<<(char C) { return (*this += C); } 113 114 OutputStream &operator<<(long long N) { 115 if (N < 0) 116 writeUnsigned(static_cast<unsigned long long>(-N), true); 117 else 118 writeUnsigned(static_cast<unsigned long long>(N)); 119 return *this; 120 } 121 122 OutputStream &operator<<(unsigned long long N) { 123 writeUnsigned(N, false); 124 return *this; 125 } 126 127 OutputStream &operator<<(long N) { 128 return this->operator<<(static_cast<long long>(N)); 129 } 130 131 OutputStream &operator<<(unsigned long N) { 132 return this->operator<<(static_cast<unsigned long long>(N)); 133 } 134 135 OutputStream &operator<<(int N) { 136 return this->operator<<(static_cast<long long>(N)); 137 } 138 139 OutputStream &operator<<(unsigned int N) { 140 return this->operator<<(static_cast<unsigned long long>(N)); 141 } 142 getCurrentPosition()143 size_t getCurrentPosition() const { return CurrentPosition; } setCurrentPosition(size_t NewPos)144 void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; } 145 back()146 char back() const { 147 return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0'; 148 } 149 empty()150 bool empty() const { return CurrentPosition == 0; } 151 getBuffer()152 char *getBuffer() { return Buffer; } getBufferEnd()153 char *getBufferEnd() { return Buffer + CurrentPosition - 1; } getBufferCapacity()154 size_t getBufferCapacity() { return BufferCapacity; } 155 }; 156 157 template <class T> class SwapAndRestore { 158 T &Restore; 159 T OriginalValue; 160 bool ShouldRestore = true; 161 162 public: SwapAndRestore(T & Restore_)163 SwapAndRestore(T &Restore_) : SwapAndRestore(Restore_, Restore_) {} 164 SwapAndRestore(T & Restore_,T NewVal)165 SwapAndRestore(T &Restore_, T NewVal) 166 : Restore(Restore_), OriginalValue(Restore) { 167 Restore = std::move(NewVal); 168 } ~SwapAndRestore()169 ~SwapAndRestore() { 170 if (ShouldRestore) 171 Restore = std::move(OriginalValue); 172 } 173 shouldRestore(bool ShouldRestore_)174 void shouldRestore(bool ShouldRestore_) { ShouldRestore = ShouldRestore_; } 175 restoreNow(bool Force)176 void restoreNow(bool Force) { 177 if (!Force && !ShouldRestore) 178 return; 179 180 Restore = std::move(OriginalValue); 181 ShouldRestore = false; 182 } 183 184 SwapAndRestore(const SwapAndRestore &) = delete; 185 SwapAndRestore &operator=(const SwapAndRestore &) = delete; 186 }; 187 188 #endif 189