11fd87a68SDimitry Andric //===--- Utility.h -------------------*- mode:c++;eval:(read-only-mode) -*-===// 21fd87a68SDimitry Andric // Do not edit! See README.txt. 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 91fd87a68SDimitry Andric // Provide some utility classes for use in the demangler. 101fd87a68SDimitry Andric // There are two copies of this file in the source tree. The one in libcxxabi 111fd87a68SDimitry Andric // is the original and the one in llvm is the copy. Use cp-to-llvm.sh to update 121fd87a68SDimitry Andric // the copy. See README.txt for more details. 130b57cec5SDimitry Andric // 140b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 150b57cec5SDimitry Andric 16bdd1243dSDimitry Andric #ifndef DEMANGLE_UTILITY_H 17bdd1243dSDimitry Andric #define DEMANGLE_UTILITY_H 180b57cec5SDimitry Andric 1906c3fb27SDimitry Andric #include "DemangleConfig.h" 2006c3fb27SDimitry Andric 2104eeddc0SDimitry Andric #include <array> 220b57cec5SDimitry Andric #include <cstdint> 230b57cec5SDimitry Andric #include <cstdlib> 240b57cec5SDimitry Andric #include <cstring> 250b57cec5SDimitry Andric #include <limits> 2606c3fb27SDimitry Andric #include <string_view> 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric DEMANGLE_NAMESPACE_BEGIN 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric // Stream that AST nodes write their string representation into after the AST 310b57cec5SDimitry Andric // has been parsed. 32349cc55cSDimitry Andric class OutputBuffer { 33480093f4SDimitry Andric char *Buffer = nullptr; 34480093f4SDimitry Andric size_t CurrentPosition = 0; 35480093f4SDimitry Andric size_t BufferCapacity = 0; 360b57cec5SDimitry Andric 3781ad6265SDimitry Andric // Ensure there are at least N more positions in the buffer. grow(size_t N)380b57cec5SDimitry Andric void grow(size_t N) { 3981ad6265SDimitry Andric size_t Need = N + CurrentPosition; 4081ad6265SDimitry Andric if (Need > BufferCapacity) { 4181ad6265SDimitry Andric // Reduce the number of reallocations, with a bit of hysteresis. The 4281ad6265SDimitry Andric // number here is chosen so the first allocation will more-than-likely not 4381ad6265SDimitry Andric // allocate more than 1K. 4481ad6265SDimitry Andric Need += 1024 - 32; 450b57cec5SDimitry Andric BufferCapacity *= 2; 4681ad6265SDimitry Andric if (BufferCapacity < Need) 4781ad6265SDimitry Andric BufferCapacity = Need; 480b57cec5SDimitry Andric Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity)); 490b57cec5SDimitry Andric if (Buffer == nullptr) 50*5f757f3fSDimitry Andric std::abort(); 510b57cec5SDimitry Andric } 520b57cec5SDimitry Andric } 530b57cec5SDimitry Andric 5481ad6265SDimitry Andric OutputBuffer &writeUnsigned(uint64_t N, bool isNeg = false) { 5504eeddc0SDimitry Andric std::array<char, 21> Temp; 5604eeddc0SDimitry Andric char *TempPtr = Temp.data() + Temp.size(); 570b57cec5SDimitry Andric 5881ad6265SDimitry Andric // Output at least one character. 5981ad6265SDimitry Andric do { 60e8d8bef9SDimitry Andric *--TempPtr = char('0' + N % 10); 610b57cec5SDimitry Andric N /= 10; 6281ad6265SDimitry Andric } while (N); 630b57cec5SDimitry Andric 6481ad6265SDimitry Andric // Add negative sign. 650b57cec5SDimitry Andric if (isNeg) 660b57cec5SDimitry Andric *--TempPtr = '-'; 6781ad6265SDimitry Andric 6806c3fb27SDimitry Andric return operator+=( 6906c3fb27SDimitry Andric std::string_view(TempPtr, Temp.data() + Temp.size() - TempPtr)); 700b57cec5SDimitry Andric } 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric public: OutputBuffer(char * StartBuf,size_t Size)73349cc55cSDimitry Andric OutputBuffer(char *StartBuf, size_t Size) 74bdd1243dSDimitry Andric : Buffer(StartBuf), BufferCapacity(Size) {} OutputBuffer(char * StartBuf,size_t * SizePtr)75bdd1243dSDimitry Andric OutputBuffer(char *StartBuf, size_t *SizePtr) 76bdd1243dSDimitry Andric : OutputBuffer(StartBuf, StartBuf ? *SizePtr : 0) {} 77349cc55cSDimitry Andric OutputBuffer() = default; 7881ad6265SDimitry Andric // Non-copyable 7981ad6265SDimitry Andric OutputBuffer(const OutputBuffer &) = delete; 8081ad6265SDimitry Andric OutputBuffer &operator=(const OutputBuffer &) = delete; 8181ad6265SDimitry Andric string_view()8206c3fb27SDimitry Andric operator std::string_view() const { 8306c3fb27SDimitry Andric return std::string_view(Buffer, CurrentPosition); 8406c3fb27SDimitry Andric } 8581ad6265SDimitry Andric 860b57cec5SDimitry Andric /// If a ParameterPackExpansion (or similar type) is encountered, the offset 870b57cec5SDimitry Andric /// into the pack that we're currently printing. 880b57cec5SDimitry Andric unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max(); 890b57cec5SDimitry Andric unsigned CurrentPackMax = std::numeric_limits<unsigned>::max(); 900b57cec5SDimitry Andric 9181ad6265SDimitry Andric /// When zero, we're printing template args and '>' needs to be parenthesized. 9281ad6265SDimitry Andric /// Use a counter so we can simply increment inside parentheses. 9381ad6265SDimitry Andric unsigned GtIsGt = 1; 9481ad6265SDimitry Andric isGtInsideTemplateArgs()9581ad6265SDimitry Andric bool isGtInsideTemplateArgs() const { return GtIsGt == 0; } 9681ad6265SDimitry Andric 9781ad6265SDimitry Andric void printOpen(char Open = '(') { 9881ad6265SDimitry Andric GtIsGt++; 9981ad6265SDimitry Andric *this += Open; 10081ad6265SDimitry Andric } 10181ad6265SDimitry Andric void printClose(char Close = ')') { 10281ad6265SDimitry Andric GtIsGt--; 10381ad6265SDimitry Andric *this += Close; 10481ad6265SDimitry Andric } 10581ad6265SDimitry Andric 10606c3fb27SDimitry Andric OutputBuffer &operator+=(std::string_view R) { 10781ad6265SDimitry Andric if (size_t Size = R.size()) { 1080b57cec5SDimitry Andric grow(Size); 10906c3fb27SDimitry Andric std::memcpy(Buffer + CurrentPosition, &*R.begin(), Size); 1100b57cec5SDimitry Andric CurrentPosition += Size; 11181ad6265SDimitry Andric } 1120b57cec5SDimitry Andric return *this; 1130b57cec5SDimitry Andric } 1140b57cec5SDimitry Andric 115349cc55cSDimitry Andric OutputBuffer &operator+=(char C) { 1160b57cec5SDimitry Andric grow(1); 1170b57cec5SDimitry Andric Buffer[CurrentPosition++] = C; 1180b57cec5SDimitry Andric return *this; 1190b57cec5SDimitry Andric } 1200b57cec5SDimitry Andric prepend(std::string_view R)12106c3fb27SDimitry Andric OutputBuffer &prepend(std::string_view R) { 122349cc55cSDimitry Andric size_t Size = R.size(); 1230b57cec5SDimitry Andric 124349cc55cSDimitry Andric grow(Size); 125349cc55cSDimitry Andric std::memmove(Buffer + Size, Buffer, CurrentPosition); 12606c3fb27SDimitry Andric std::memcpy(Buffer, &*R.begin(), Size); 127349cc55cSDimitry Andric CurrentPosition += Size; 128349cc55cSDimitry Andric 129349cc55cSDimitry Andric return *this; 130349cc55cSDimitry Andric } 131349cc55cSDimitry Andric 13206c3fb27SDimitry Andric OutputBuffer &operator<<(std::string_view R) { return (*this += R); } 13381ad6265SDimitry Andric 134349cc55cSDimitry Andric OutputBuffer &operator<<(char C) { return (*this += C); } 135349cc55cSDimitry Andric 136349cc55cSDimitry Andric OutputBuffer &operator<<(long long N) { 13781ad6265SDimitry Andric return writeUnsigned(static_cast<unsigned long long>(std::abs(N)), N < 0); 1380b57cec5SDimitry Andric } 1390b57cec5SDimitry Andric 140349cc55cSDimitry Andric OutputBuffer &operator<<(unsigned long long N) { 14181ad6265SDimitry Andric return writeUnsigned(N, false); 1420b57cec5SDimitry Andric } 1430b57cec5SDimitry Andric 144349cc55cSDimitry Andric OutputBuffer &operator<<(long N) { 1450b57cec5SDimitry Andric return this->operator<<(static_cast<long long>(N)); 1460b57cec5SDimitry Andric } 1470b57cec5SDimitry Andric 148349cc55cSDimitry Andric OutputBuffer &operator<<(unsigned long N) { 1490b57cec5SDimitry Andric return this->operator<<(static_cast<unsigned long long>(N)); 1500b57cec5SDimitry Andric } 1510b57cec5SDimitry Andric 152349cc55cSDimitry Andric OutputBuffer &operator<<(int N) { 1530b57cec5SDimitry Andric return this->operator<<(static_cast<long long>(N)); 1540b57cec5SDimitry Andric } 1550b57cec5SDimitry Andric 156349cc55cSDimitry Andric OutputBuffer &operator<<(unsigned int N) { 1570b57cec5SDimitry Andric return this->operator<<(static_cast<unsigned long long>(N)); 1580b57cec5SDimitry Andric } 1590b57cec5SDimitry Andric insert(size_t Pos,const char * S,size_t N)160349cc55cSDimitry Andric void insert(size_t Pos, const char *S, size_t N) { 161*5f757f3fSDimitry Andric DEMANGLE_ASSERT(Pos <= CurrentPosition, ""); 162349cc55cSDimitry Andric if (N == 0) 163349cc55cSDimitry Andric return; 164349cc55cSDimitry Andric grow(N); 165349cc55cSDimitry Andric std::memmove(Buffer + Pos + N, Buffer + Pos, CurrentPosition - Pos); 166349cc55cSDimitry Andric std::memcpy(Buffer + Pos, S, N); 167349cc55cSDimitry Andric CurrentPosition += N; 168349cc55cSDimitry Andric } 169349cc55cSDimitry Andric getCurrentPosition()1700b57cec5SDimitry Andric size_t getCurrentPosition() const { return CurrentPosition; } setCurrentPosition(size_t NewPos)1710b57cec5SDimitry Andric void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; } 1720b57cec5SDimitry Andric back()1730b57cec5SDimitry Andric char back() const { 174*5f757f3fSDimitry Andric DEMANGLE_ASSERT(CurrentPosition, ""); 17581ad6265SDimitry Andric return Buffer[CurrentPosition - 1]; 1760b57cec5SDimitry Andric } 1770b57cec5SDimitry Andric empty()1780b57cec5SDimitry Andric bool empty() const { return CurrentPosition == 0; } 1790b57cec5SDimitry Andric getBuffer()1800b57cec5SDimitry Andric char *getBuffer() { return Buffer; } getBufferEnd()1810b57cec5SDimitry Andric char *getBufferEnd() { return Buffer + CurrentPosition - 1; } getBufferCapacity()182480093f4SDimitry Andric size_t getBufferCapacity() const { return BufferCapacity; } 1830b57cec5SDimitry Andric }; 1840b57cec5SDimitry Andric 18581ad6265SDimitry Andric template <class T> class ScopedOverride { 18681ad6265SDimitry Andric T &Loc; 18781ad6265SDimitry Andric T Original; 1880b57cec5SDimitry Andric 1890b57cec5SDimitry Andric public: ScopedOverride(T & Loc_)19081ad6265SDimitry Andric ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {} 1910b57cec5SDimitry Andric ScopedOverride(T & Loc_,T NewVal)19281ad6265SDimitry Andric ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) { 19381ad6265SDimitry Andric Loc_ = std::move(NewVal); 1940b57cec5SDimitry Andric } ~ScopedOverride()19581ad6265SDimitry Andric ~ScopedOverride() { Loc = std::move(Original); } 1960b57cec5SDimitry Andric 19781ad6265SDimitry Andric ScopedOverride(const ScopedOverride &) = delete; 19881ad6265SDimitry Andric ScopedOverride &operator=(const ScopedOverride &) = delete; 1990b57cec5SDimitry Andric }; 2000b57cec5SDimitry Andric 2010b57cec5SDimitry Andric DEMANGLE_NAMESPACE_END 2020b57cec5SDimitry Andric 2030b57cec5SDimitry Andric #endif 204