//===--- 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. // SPDX-FileCopyrightText: Part of the LLVM Project // 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 #include #include #include #include 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(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::max(); unsigned CurrentPackMax = std::numeric_limits::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(-N), true); else writeUnsigned(static_cast(N)); return *this; } OutputStream &operator<<(unsigned long long N) { writeUnsigned(N, false); return *this; } OutputStream &operator<<(long N) { return this->operator<<(static_cast(N)); } OutputStream &operator<<(unsigned long N) { return this->operator<<(static_cast(N)); } OutputStream &operator<<(int N) { return this->operator<<(static_cast(N)); } OutputStream &operator<<(unsigned int N) { return this->operator<<(static_cast(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 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(std::malloc(InitSize)); if (Buf == nullptr) return false; BufferSize = InitSize; } else BufferSize = *N; S.reset(Buf, BufferSize); return true; } DEMANGLE_NAMESPACE_END #endif