xref: /freebsd/contrib/llvm-project/llvm/include/llvm/Demangle/Utility.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===--- Utility.h -------------------*- mode:c++;eval:(read-only-mode) -*-===//
2 //       Do not edit! See README.txt.
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Provide some utility classes for use in the demangler.
10 // There are two copies of this file in the source tree.  The one in libcxxabi
11 // is the original and the one in llvm is the copy.  Use cp-to-llvm.sh to update
12 // the copy.  See README.txt for more details.
13 //
14 //===----------------------------------------------------------------------===//
15 
16 #ifndef DEMANGLE_UTILITY_H
17 #define DEMANGLE_UTILITY_H
18 
19 #include "DemangleConfig.h"
20 
21 #include <array>
22 #include <cstdint>
23 #include <cstdlib>
24 #include <cstring>
25 #include <limits>
26 #include <string_view>
27 
28 DEMANGLE_NAMESPACE_BEGIN
29 
30 class Node;
31 
32 // Stream that AST nodes write their string representation into after the AST
33 // has been parsed.
34 class OutputBuffer {
35   char *Buffer = nullptr;
36   size_t CurrentPosition = 0;
37   size_t BufferCapacity = 0;
38 
39   // Ensure there are at least N more positions in the buffer.
grow(size_t N)40   void grow(size_t N) {
41     size_t Need = N + CurrentPosition;
42     if (Need > BufferCapacity) {
43       // Reduce the number of reallocations, with a bit of hysteresis. The
44       // number here is chosen so the first allocation will more-than-likely not
45       // allocate more than 1K.
46       Need += 1024 - 32;
47       BufferCapacity *= 2;
48       if (BufferCapacity < Need)
49         BufferCapacity = Need;
50       Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));
51       if (Buffer == nullptr)
52         std::abort();
53     }
54   }
55 
56   OutputBuffer &writeUnsigned(uint64_t N, bool isNeg = false) {
57     std::array<char, 21> Temp;
58     char *TempPtr = Temp.data() + Temp.size();
59 
60     // Output at least one character.
61     do {
62       *--TempPtr = char('0' + N % 10);
63       N /= 10;
64     } while (N);
65 
66     // Add negative sign.
67     if (isNeg)
68       *--TempPtr = '-';
69 
70     return operator+=(
71         std::string_view(TempPtr, Temp.data() + Temp.size() - TempPtr));
72   }
73 
74 public:
OutputBuffer(char * StartBuf,size_t Size)75   OutputBuffer(char *StartBuf, size_t Size)
76       : Buffer(StartBuf), BufferCapacity(Size) {}
OutputBuffer(char * StartBuf,size_t * SizePtr)77   OutputBuffer(char *StartBuf, size_t *SizePtr)
78       : OutputBuffer(StartBuf, StartBuf ? *SizePtr : 0) {}
79   OutputBuffer() = default;
80   // Non-copyable
81   OutputBuffer(const OutputBuffer &) = delete;
82   OutputBuffer &operator=(const OutputBuffer &) = delete;
83 
~OutputBuffer()84   virtual ~OutputBuffer() {}
85 
string_view()86   operator std::string_view() const {
87     return std::string_view(Buffer, CurrentPosition);
88   }
89 
90   /// Called by the demangler when printing the demangle tree. By
91   /// default calls into \c Node::print{Left|Right} but can be overriden
92   /// by clients to track additional state when printing the demangled name.
93   virtual void printLeft(const Node &N);
94   virtual void printRight(const Node &N);
95 
96   /// Called when we write to this object anywhere other than the end.
notifyInsertion(size_t,size_t)97   virtual void notifyInsertion(size_t /*Position*/, size_t /*Count*/) {}
98 
99   /// Called when we make the \c CurrentPosition of this object smaller.
notifyDeletion(size_t,size_t)100   virtual void notifyDeletion(size_t /*OldPos*/, size_t /*NewPos*/) {}
101 
102   /// If a ParameterPackExpansion (or similar type) is encountered, the offset
103   /// into the pack that we're currently printing.
104   unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
105   unsigned CurrentPackMax = std::numeric_limits<unsigned>::max();
106 
107   /// When zero, we're printing template args and '>' needs to be parenthesized.
108   /// Use a counter so we can simply increment inside parentheses.
109   unsigned GtIsGt = 1;
110 
isGtInsideTemplateArgs()111   bool isGtInsideTemplateArgs() const { return GtIsGt == 0; }
112 
113   void printOpen(char Open = '(') {
114     GtIsGt++;
115     *this += Open;
116   }
117   void printClose(char Close = ')') {
118     GtIsGt--;
119     *this += Close;
120   }
121 
122   OutputBuffer &operator+=(std::string_view R) {
123     if (size_t Size = R.size()) {
124       grow(Size);
125       std::memcpy(Buffer + CurrentPosition, &*R.begin(), Size);
126       CurrentPosition += Size;
127     }
128     return *this;
129   }
130 
131   OutputBuffer &operator+=(char C) {
132     grow(1);
133     Buffer[CurrentPosition++] = C;
134     return *this;
135   }
136 
prepend(std::string_view R)137   OutputBuffer &prepend(std::string_view R) {
138     size_t Size = R.size();
139     if (!Size)
140       return *this;
141 
142     grow(Size);
143     std::memmove(Buffer + Size, Buffer, CurrentPosition);
144     std::memcpy(Buffer, &*R.begin(), Size);
145     CurrentPosition += Size;
146 
147     notifyInsertion(/*Position=*/0, /*Count=*/Size);
148 
149     return *this;
150   }
151 
152   OutputBuffer &operator<<(std::string_view R) { return (*this += R); }
153 
154   OutputBuffer &operator<<(char C) { return (*this += C); }
155 
156   OutputBuffer &operator<<(long long N) {
157     return writeUnsigned(static_cast<unsigned long long>(std::abs(N)), N < 0);
158   }
159 
160   OutputBuffer &operator<<(unsigned long long N) {
161     return writeUnsigned(N, false);
162   }
163 
164   OutputBuffer &operator<<(long N) {
165     return this->operator<<(static_cast<long long>(N));
166   }
167 
168   OutputBuffer &operator<<(unsigned long N) {
169     return this->operator<<(static_cast<unsigned long long>(N));
170   }
171 
172   OutputBuffer &operator<<(int N) {
173     return this->operator<<(static_cast<long long>(N));
174   }
175 
176   OutputBuffer &operator<<(unsigned int N) {
177     return this->operator<<(static_cast<unsigned long long>(N));
178   }
179 
insert(size_t Pos,const char * S,size_t N)180   void insert(size_t Pos, const char *S, size_t N) {
181     DEMANGLE_ASSERT(Pos <= CurrentPosition, "");
182     if (N == 0)
183       return;
184 
185     grow(N);
186     std::memmove(Buffer + Pos + N, Buffer + Pos, CurrentPosition - Pos);
187     std::memcpy(Buffer + Pos, S, N);
188     CurrentPosition += N;
189 
190     notifyInsertion(Pos, N);
191   }
192 
getCurrentPosition()193   size_t getCurrentPosition() const { return CurrentPosition; }
setCurrentPosition(size_t NewPos)194   void setCurrentPosition(size_t NewPos) {
195     notifyDeletion(CurrentPosition, NewPos);
196     CurrentPosition = NewPos;
197   }
198 
back()199   char back() const {
200     DEMANGLE_ASSERT(CurrentPosition, "");
201     return Buffer[CurrentPosition - 1];
202   }
203 
empty()204   bool empty() const { return CurrentPosition == 0; }
205 
getBuffer()206   char *getBuffer() { return Buffer; }
getBufferEnd()207   char *getBufferEnd() { return Buffer + CurrentPosition - 1; }
getBufferCapacity()208   size_t getBufferCapacity() const { return BufferCapacity; }
209 };
210 
211 template <class T> class ScopedOverride {
212   T &Loc;
213   T Original;
214 
215 public:
ScopedOverride(T & Loc_)216   ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {}
217 
ScopedOverride(T & Loc_,T NewVal)218   ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) {
219     Loc_ = std::move(NewVal);
220   }
~ScopedOverride()221   ~ScopedOverride() { Loc = std::move(Original); }
222 
223   ScopedOverride(const ScopedOverride &) = delete;
224   ScopedOverride &operator=(const ScopedOverride &) = delete;
225 };
226 
227 DEMANGLE_NAMESPACE_END
228 
229 #endif
230