xref: /freebsd-src/contrib/llvm-project/llvm/include/llvm/Demangle/Utility.h (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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