| 
									
										
										
										
											2023-01-13 21:06:13 +00:00
										 |  |  | //===--- Utility.h ----------------------------------------------*- C++ -*-===//
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | 
					
						
							|  |  |  | // See https://llvm.org/LICENSE.txt for license information.
 | 
					
						
							| 
									
										
										
										
											2023-01-21 06:19:43 +00:00
										 |  |  | // SPDX-FileCopyrightText: Part of the LLVM Project
 | 
					
						
							| 
									
										
										
										
											2023-01-13 21:06:13 +00:00
										 |  |  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //===----------------------------------------------------------------------===//
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Provide some utility classes for use in the demangler(s).
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //===----------------------------------------------------------------------===//
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifndef DEMANGLE_UTILITY_H
 | 
					
						
							|  |  |  | #define DEMANGLE_UTILITY_H
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "StringView.h"
 | 
					
						
							|  |  |  | #include <cstdint>
 | 
					
						
							|  |  |  | #include <cstdlib>
 | 
					
						
							|  |  |  | #include <cstring>
 | 
					
						
							|  |  |  | #include <iterator>
 | 
					
						
							|  |  |  | #include <limits>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | DEMANGLE_NAMESPACE_BEGIN | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Stream that AST nodes write their string representation into after the AST
 | 
					
						
							|  |  |  | // has been parsed.
 | 
					
						
							|  |  |  | class OutputStream { | 
					
						
							|  |  |  |   char *Buffer; | 
					
						
							|  |  |  |   size_t CurrentPosition; | 
					
						
							|  |  |  |   size_t BufferCapacity; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Ensure there is at least n more positions in buffer.
 | 
					
						
							|  |  |  |   void grow(size_t N) { | 
					
						
							|  |  |  |     if (N + CurrentPosition >= BufferCapacity) { | 
					
						
							|  |  |  |       BufferCapacity *= 2; | 
					
						
							|  |  |  |       if (BufferCapacity < N + CurrentPosition) | 
					
						
							|  |  |  |         BufferCapacity = N + CurrentPosition; | 
					
						
							|  |  |  |       Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity)); | 
					
						
							|  |  |  |       if (Buffer == nullptr) | 
					
						
							|  |  |  |         std::terminate(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void writeUnsigned(uint64_t N, bool isNeg = false) { | 
					
						
							|  |  |  |     // Handle special case...
 | 
					
						
							|  |  |  |     if (N == 0) { | 
					
						
							|  |  |  |       *this << '0'; | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     char Temp[21]; | 
					
						
							|  |  |  |     char *TempPtr = std::end(Temp); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while (N) { | 
					
						
							|  |  |  |       *--TempPtr = '0' + char(N % 10); | 
					
						
							|  |  |  |       N /= 10; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Add negative sign...
 | 
					
						
							|  |  |  |     if (isNeg) | 
					
						
							|  |  |  |       *--TempPtr = '-'; | 
					
						
							|  |  |  |     this->operator<<(StringView(TempPtr, std::end(Temp))); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |   OutputStream(char *StartBuf, size_t Size) | 
					
						
							|  |  |  |       : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {} | 
					
						
							|  |  |  |   OutputStream() = default; | 
					
						
							|  |  |  |   void reset(char *Buffer_, size_t BufferCapacity_) { | 
					
						
							|  |  |  |     CurrentPosition = 0; | 
					
						
							|  |  |  |     Buffer = Buffer_; | 
					
						
							|  |  |  |     BufferCapacity = BufferCapacity_; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /// If a ParameterPackExpansion (or similar type) is encountered, the offset
 | 
					
						
							|  |  |  |   /// into the pack that we're currently printing.
 | 
					
						
							|  |  |  |   unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max(); | 
					
						
							|  |  |  |   unsigned CurrentPackMax = std::numeric_limits<unsigned>::max(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   OutputStream &operator+=(StringView R) { | 
					
						
							|  |  |  |     size_t Size = R.size(); | 
					
						
							|  |  |  |     if (Size == 0) | 
					
						
							|  |  |  |       return *this; | 
					
						
							|  |  |  |     grow(Size); | 
					
						
							|  |  |  |     std::memmove(Buffer + CurrentPosition, R.begin(), Size); | 
					
						
							|  |  |  |     CurrentPosition += Size; | 
					
						
							|  |  |  |     return *this; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   OutputStream &operator+=(char C) { | 
					
						
							|  |  |  |     grow(1); | 
					
						
							|  |  |  |     Buffer[CurrentPosition++] = C; | 
					
						
							|  |  |  |     return *this; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   OutputStream &operator<<(StringView R) { return (*this += R); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   OutputStream &operator<<(char C) { return (*this += C); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   OutputStream &operator<<(long long N) { | 
					
						
							|  |  |  |     if (N < 0) | 
					
						
							|  |  |  |       writeUnsigned(static_cast<unsigned long long>(-N), true); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       writeUnsigned(static_cast<unsigned long long>(N)); | 
					
						
							|  |  |  |     return *this; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   OutputStream &operator<<(unsigned long long N) { | 
					
						
							|  |  |  |     writeUnsigned(N, false); | 
					
						
							|  |  |  |     return *this; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   OutputStream &operator<<(long N) { | 
					
						
							|  |  |  |     return this->operator<<(static_cast<long long>(N)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   OutputStream &operator<<(unsigned long N) { | 
					
						
							|  |  |  |     return this->operator<<(static_cast<unsigned long long>(N)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   OutputStream &operator<<(int N) { | 
					
						
							|  |  |  |     return this->operator<<(static_cast<long long>(N)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   OutputStream &operator<<(unsigned int N) { | 
					
						
							|  |  |  |     return this->operator<<(static_cast<unsigned long long>(N)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   size_t getCurrentPosition() const { return CurrentPosition; } | 
					
						
							|  |  |  |   void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   char back() const { | 
					
						
							|  |  |  |     return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0'; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   bool empty() const { return CurrentPosition == 0; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   char *getBuffer() { return Buffer; } | 
					
						
							|  |  |  |   char *getBufferEnd() { return Buffer + CurrentPosition - 1; } | 
					
						
							|  |  |  |   size_t getBufferCapacity() { return BufferCapacity; } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <class T> class SwapAndRestore { | 
					
						
							|  |  |  |   T &Restore; | 
					
						
							|  |  |  |   T OriginalValue; | 
					
						
							|  |  |  |   bool ShouldRestore = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |   SwapAndRestore(T &Restore_) : SwapAndRestore(Restore_, Restore_) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   SwapAndRestore(T &Restore_, T NewVal) | 
					
						
							|  |  |  |       : Restore(Restore_), OriginalValue(Restore) { | 
					
						
							|  |  |  |     Restore = std::move(NewVal); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   ~SwapAndRestore() { | 
					
						
							|  |  |  |     if (ShouldRestore) | 
					
						
							|  |  |  |       Restore = std::move(OriginalValue); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void shouldRestore(bool ShouldRestore_) { ShouldRestore = ShouldRestore_; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void restoreNow(bool Force) { | 
					
						
							|  |  |  |     if (!Force && !ShouldRestore) | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Restore = std::move(OriginalValue); | 
					
						
							|  |  |  |     ShouldRestore = false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   SwapAndRestore(const SwapAndRestore &) = delete; | 
					
						
							|  |  |  |   SwapAndRestore &operator=(const SwapAndRestore &) = delete; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | inline bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S, | 
					
						
							|  |  |  |                                    size_t InitSize) { | 
					
						
							|  |  |  |   size_t BufferSize; | 
					
						
							|  |  |  |   if (Buf == nullptr) { | 
					
						
							|  |  |  |     Buf = static_cast<char *>(std::malloc(InitSize)); | 
					
						
							|  |  |  |     if (Buf == nullptr) | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     BufferSize = InitSize; | 
					
						
							|  |  |  |   } else | 
					
						
							|  |  |  |     BufferSize = *N; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   S.reset(Buf, BufferSize); | 
					
						
							|  |  |  |   return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | DEMANGLE_NAMESPACE_END | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif
 |