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 LLVM_DEMANGLE_UTILITY_H
17 #define LLVM_DEMANGLE_UTILITY_H
18
19 #include "StringView.h"
20 #include <array>
21 #include <cstdint>
22 #include <cstdlib>
23 #include <cstring>
24 #include <exception>
25 #include <limits>
26
27 DEMANGLE_NAMESPACE_BEGIN
28
29 // Stream that AST nodes write their string representation into after the AST
30 // has been parsed.
31 class OutputBuffer {
32 char *Buffer = nullptr;
33 size_t CurrentPosition = 0;
34 size_t BufferCapacity = 0;
35
36 // Ensure there are at least N more positions in the buffer.
grow(size_t N)37 void grow(size_t N) {
38 size_t Need = N + CurrentPosition;
39 if (Need > BufferCapacity) {
40 // Reduce the number of reallocations, with a bit of hysteresis. The
41 // number here is chosen so the first allocation will more-than-likely not
42 // allocate more than 1K.
43 Need += 1024 - 32;
44 BufferCapacity *= 2;
45 if (BufferCapacity < Need)
46 BufferCapacity = Need;
47 Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));
48 if (Buffer == nullptr)
49 std::terminate();
50 }
51 }
52
53 OutputBuffer &writeUnsigned(uint64_t N, bool isNeg = false) {
54 std::array<char, 21> Temp;
55 char *TempPtr = Temp.data() + Temp.size();
56
57 // Output at least one character.
58 do {
59 *--TempPtr = char('0' + N % 10);
60 N /= 10;
61 } while (N);
62
63 // Add negative sign.
64 if (isNeg)
65 *--TempPtr = '-';
66
67 return operator+=(StringView(TempPtr, Temp.data() + Temp.size()));
68 }
69
70 public:
OutputBuffer(char * StartBuf,size_t Size)71 OutputBuffer(char *StartBuf, size_t Size)
72 : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {}
73 OutputBuffer() = default;
74 // Non-copyable
75 OutputBuffer(const OutputBuffer &) = delete;
76 OutputBuffer &operator=(const OutputBuffer &) = delete;
77
StringView()78 operator StringView() const { return StringView(Buffer, CurrentPosition); }
79
reset(char * Buffer_,size_t BufferCapacity_)80 void reset(char *Buffer_, size_t BufferCapacity_) {
81 CurrentPosition = 0;
82 Buffer = Buffer_;
83 BufferCapacity = BufferCapacity_;
84 }
85
86 /// If a ParameterPackExpansion (or similar type) is encountered, the offset
87 /// into the pack that we're currently printing.
88 unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
89 unsigned CurrentPackMax = std::numeric_limits<unsigned>::max();
90
91 /// When zero, we're printing template args and '>' needs to be parenthesized.
92 /// Use a counter so we can simply increment inside parentheses.
93 unsigned GtIsGt = 1;
94
isGtInsideTemplateArgs()95 bool isGtInsideTemplateArgs() const { return GtIsGt == 0; }
96
97 void printOpen(char Open = '(') {
98 GtIsGt++;
99 *this += Open;
100 }
101 void printClose(char Close = ')') {
102 GtIsGt--;
103 *this += Close;
104 }
105
106 OutputBuffer &operator+=(StringView R) {
107 if (size_t Size = R.size()) {
108 grow(Size);
109 std::memcpy(Buffer + CurrentPosition, R.begin(), Size);
110 CurrentPosition += Size;
111 }
112 return *this;
113 }
114
115 OutputBuffer &operator+=(char C) {
116 grow(1);
117 Buffer[CurrentPosition++] = C;
118 return *this;
119 }
120
prepend(StringView R)121 OutputBuffer &prepend(StringView R) {
122 size_t Size = R.size();
123
124 grow(Size);
125 std::memmove(Buffer + Size, Buffer, CurrentPosition);
126 std::memcpy(Buffer, R.begin(), Size);
127 CurrentPosition += Size;
128
129 return *this;
130 }
131
132 OutputBuffer &operator<<(StringView R) { return (*this += R); }
133
134 OutputBuffer &operator<<(char C) { return (*this += C); }
135
136 OutputBuffer &operator<<(long long N) {
137 return writeUnsigned(static_cast<unsigned long long>(std::abs(N)), N < 0);
138 }
139
140 OutputBuffer &operator<<(unsigned long long N) {
141 return writeUnsigned(N, false);
142 }
143
144 OutputBuffer &operator<<(long N) {
145 return this->operator<<(static_cast<long long>(N));
146 }
147
148 OutputBuffer &operator<<(unsigned long N) {
149 return this->operator<<(static_cast<unsigned long long>(N));
150 }
151
152 OutputBuffer &operator<<(int N) {
153 return this->operator<<(static_cast<long long>(N));
154 }
155
156 OutputBuffer &operator<<(unsigned int N) {
157 return this->operator<<(static_cast<unsigned long long>(N));
158 }
159
insert(size_t Pos,const char * S,size_t N)160 void insert(size_t Pos, const char *S, size_t N) {
161 assert(Pos <= CurrentPosition);
162 if (N == 0)
163 return;
164 grow(N);
165 std::memmove(Buffer + Pos + N, Buffer + Pos, CurrentPosition - Pos);
166 std::memcpy(Buffer + Pos, S, N);
167 CurrentPosition += N;
168 }
169
getCurrentPosition()170 size_t getCurrentPosition() const { return CurrentPosition; }
setCurrentPosition(size_t NewPos)171 void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
172
back()173 char back() const {
174 assert(CurrentPosition);
175 return Buffer[CurrentPosition - 1];
176 }
177
empty()178 bool empty() const { return CurrentPosition == 0; }
179
getBuffer()180 char *getBuffer() { return Buffer; }
getBufferEnd()181 char *getBufferEnd() { return Buffer + CurrentPosition - 1; }
getBufferCapacity()182 size_t getBufferCapacity() const { return BufferCapacity; }
183 };
184
185 template <class T> class ScopedOverride {
186 T &Loc;
187 T Original;
188
189 public:
ScopedOverride(T & Loc_)190 ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {}
191
ScopedOverride(T & Loc_,T NewVal)192 ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) {
193 Loc_ = std::move(NewVal);
194 }
~ScopedOverride()195 ~ScopedOverride() { Loc = std::move(Original); }
196
197 ScopedOverride(const ScopedOverride &) = delete;
198 ScopedOverride &operator=(const ScopedOverride &) = delete;
199 };
200
initializeOutputBuffer(char * Buf,size_t * N,OutputBuffer & OB,size_t InitSize)201 inline bool initializeOutputBuffer(char *Buf, size_t *N, OutputBuffer &OB,
202 size_t InitSize) {
203 size_t BufferSize;
204 if (Buf == nullptr) {
205 Buf = static_cast<char *>(std::malloc(InitSize));
206 if (Buf == nullptr)
207 return false;
208 BufferSize = InitSize;
209 } else
210 BufferSize = *N;
211
212 OB.reset(Buf, BufferSize);
213 return true;
214 }
215
216 DEMANGLE_NAMESPACE_END
217
218 #endif
219