//===--- Utility.h -------------------*- mode:c++;eval:(read-only-mode) -*-===// // Do not edit! See README.txt. // 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. // There are two copies of this file in the source tree. The one in libcxxabi // is the original and the one in llvm is the copy. Use cp-to-llvm.sh to update // the copy. See README.txt for more details. // //===----------------------------------------------------------------------===// #ifndef DEMANGLE_UTILITY_H #define DEMANGLE_UTILITY_H #include "DemangleConfig.h" #include <array> #include <cassert> #include <cstdint> #include <cstdlib> #include <cstring> #include <exception> #include <limits> #include <string_view> DEMANGLE_NAMESPACE_BEGIN // Stream that AST nodes write their string representation into after the AST // has been parsed. class OutputBuffer { char *Buffer = nullptr; size_t CurrentPosition = 0; size_t BufferCapacity = 0; // Ensure there are at least N more positions in the buffer. void grow(size_t N) { size_t Need = N + CurrentPosition; if (Need > BufferCapacity) { // Reduce the number of reallocations, with a bit of hysteresis. The // number here is chosen so the first allocation will more-than-likely not // allocate more than 1K. Need += 1024 - 32; BufferCapacity *= 2; if (BufferCapacity < Need) BufferCapacity = Need; Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity)); if (Buffer == nullptr) std::terminate(); } } OutputBuffer &writeUnsigned(uint64_t N, bool isNeg = false) { std::array<char, 21> Temp; char *TempPtr = Temp.data() + Temp.size(); // Output at least one character. do { *--TempPtr = char('0' + N % 10); N /= 10; } while (N); // Add negative sign. if (isNeg) *--TempPtr = '-'; return operator+=( std::string_view(TempPtr, Temp.data() + Temp.size() - TempPtr)); } public: OutputBuffer(char *StartBuf, size_t Size) : Buffer(StartBuf), BufferCapacity(Size) {} OutputBuffer(char *StartBuf, size_t *SizePtr) : OutputBuffer(StartBuf, StartBuf ? *SizePtr : 0) {} OutputBuffer() = default; // Non-copyable OutputBuffer(const OutputBuffer &) = delete; OutputBuffer &operator=(const OutputBuffer &) = delete; operator std::string_view() const { return std::string_view(Buffer, CurrentPosition); } /// 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(); /// When zero, we're printing template args and '>' needs to be parenthesized. /// Use a counter so we can simply increment inside parentheses. unsigned GtIsGt = 1; bool isGtInsideTemplateArgs() const { return GtIsGt == 0; } void printOpen(char Open = '(') { GtIsGt++; *this += Open; } void printClose(char Close = ')') { GtIsGt--; *this += Close; } OutputBuffer &operator+=(std::string_view R) { if (size_t Size = R.size()) { grow(Size); std::memcpy(Buffer + CurrentPosition, &*R.begin(), Size); CurrentPosition += Size; } return *this; } OutputBuffer &operator+=(char C) { grow(1); Buffer[CurrentPosition++] = C; return *this; } OutputBuffer &prepend(std::string_view R) { size_t Size = R.size(); grow(Size); std::memmove(Buffer + Size, Buffer, CurrentPosition); std::memcpy(Buffer, &*R.begin(), Size); CurrentPosition += Size; return *this; } OutputBuffer &operator<<(std::string_view R) { return (*this += R); } OutputBuffer &operator<<(char C) { return (*this += C); } OutputBuffer &operator<<(long long N) { return writeUnsigned(static_cast<unsigned long long>(std::abs(N)), N < 0); } OutputBuffer &operator<<(unsigned long long N) { return writeUnsigned(N, false); } OutputBuffer &operator<<(long N) { return this->operator<<(static_cast<long long>(N)); } OutputBuffer &operator<<(unsigned long N) { return this->operator<<(static_cast<unsigned long long>(N)); } OutputBuffer &operator<<(int N) { return this->operator<<(static_cast<long long>(N)); } OutputBuffer &operator<<(unsigned int N) { return this->operator<<(static_cast<unsigned long long>(N)); } void insert(size_t Pos, const char *S, size_t N) { assert(Pos <= CurrentPosition); if (N == 0) return; grow(N); std::memmove(Buffer + Pos + N, Buffer + Pos, CurrentPosition - Pos); std::memcpy(Buffer + Pos, S, N); CurrentPosition += N; } size_t getCurrentPosition() const { return CurrentPosition; } void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; } char back() const { assert(CurrentPosition); return Buffer[CurrentPosition - 1]; } bool empty() const { return CurrentPosition == 0; } char *getBuffer() { return Buffer; } char *getBufferEnd() { return Buffer + CurrentPosition - 1; } size_t getBufferCapacity() const { return BufferCapacity; } }; template <class T> class ScopedOverride { T &Loc; T Original; public: ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {} ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) { Loc_ = std::move(NewVal); } ~ScopedOverride() { Loc = std::move(Original); } ScopedOverride(const ScopedOverride &) = delete; ScopedOverride &operator=(const ScopedOverride &) = delete; }; DEMANGLE_NAMESPACE_END #endif