/src/llvm-project/libcxxabi/src/demangle/Utility.h
Line | Count | Source |
1 | | //===--- Utility.h ----------------------------------------------*- C++ -*-===// |
2 | | // |
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. |
40 | 0 | void grow(size_t N) { |
41 | 0 | size_t Need = N + CurrentPosition; |
42 | 0 | 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 | 0 | Need += 1024 - 32; |
47 | 0 | BufferCapacity *= 2; |
48 | 0 | if (BufferCapacity < Need) |
49 | 0 | BufferCapacity = Need; |
50 | 0 | Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity)); |
51 | 0 | if (Buffer == nullptr) |
52 | 0 | std::abort(); |
53 | 0 | } |
54 | 0 | } |
55 | | |
56 | 0 | OutputBuffer &writeUnsigned(uint64_t N, bool isNeg = false) { |
57 | 0 | std::array<char, 21> Temp; |
58 | 0 | char *TempPtr = Temp.data() + Temp.size(); |
59 | | |
60 | | // Output at least one character. |
61 | 0 | do { |
62 | 0 | *--TempPtr = char('0' + N % 10); |
63 | 0 | N /= 10; |
64 | 0 | } while (N); |
65 | | |
66 | | // Add negative sign. |
67 | 0 | if (isNeg) |
68 | 0 | *--TempPtr = '-'; |
69 | |
|
70 | 0 | return operator+=( |
71 | 0 | std::string_view(TempPtr, Temp.data() + Temp.size() - TempPtr)); |
72 | 0 | } |
73 | | |
74 | | public: |
75 | | OutputBuffer(char *StartBuf, size_t Size) |
76 | 0 | : Buffer(StartBuf), BufferCapacity(Size) {} |
77 | | OutputBuffer(char *StartBuf, size_t *SizePtr) |
78 | 0 | : OutputBuffer(StartBuf, StartBuf ? *SizePtr : 0) {} |
79 | | OutputBuffer() = default; |
80 | | // Non-copyable |
81 | | OutputBuffer(const OutputBuffer &) = delete; |
82 | | OutputBuffer &operator=(const OutputBuffer &) = delete; |
83 | | |
84 | 0 | virtual ~OutputBuffer() = default; |
85 | | |
86 | 0 | operator std::string_view() const { |
87 | 0 | return std::string_view(Buffer, CurrentPosition); |
88 | 0 | } |
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. |
97 | 0 | virtual void notifyInsertion(size_t /*Position*/, size_t /*Count*/) {} |
98 | | |
99 | | /// Called when we make the \c CurrentPosition of this object smaller. |
100 | 0 | 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 | | struct { |
108 | | /// The depth of '(' and ')' inside the currently printed template |
109 | | /// arguments. |
110 | | unsigned ParenDepth = 0; |
111 | | |
112 | | /// True if we're currently printing a template argument. |
113 | | bool InsideTemplate = false; |
114 | | } TemplateTracker; |
115 | | |
116 | | /// Returns true if we're currently between a '(' and ')' when printing |
117 | | /// template args. |
118 | 0 | bool isInParensInTemplateArgs() const { |
119 | 0 | return TemplateTracker.ParenDepth > 0; |
120 | 0 | } |
121 | | |
122 | | /// Returns true if we're printing template args. |
123 | 0 | bool isInsideTemplateArgs() const { return TemplateTracker.InsideTemplate; } |
124 | | |
125 | 0 | void printOpen(char Open = '(') { |
126 | 0 | if (isInsideTemplateArgs()) |
127 | 0 | TemplateTracker.ParenDepth++; |
128 | 0 | *this += Open; |
129 | 0 | } |
130 | 0 | void printClose(char Close = ')') { |
131 | 0 | if (isInsideTemplateArgs()) |
132 | 0 | TemplateTracker.ParenDepth--; |
133 | 0 | *this += Close; |
134 | 0 | } |
135 | | |
136 | 0 | OutputBuffer &operator+=(std::string_view R) { |
137 | 0 | if (size_t Size = R.size()) { |
138 | 0 | grow(Size); |
139 | 0 | std::memcpy(Buffer + CurrentPosition, &*R.begin(), Size); |
140 | 0 | CurrentPosition += Size; |
141 | 0 | } |
142 | 0 | return *this; |
143 | 0 | } |
144 | | |
145 | 0 | OutputBuffer &operator+=(char C) { |
146 | 0 | grow(1); |
147 | 0 | Buffer[CurrentPosition++] = C; |
148 | 0 | return *this; |
149 | 0 | } |
150 | | |
151 | 0 | OutputBuffer &prepend(std::string_view R) { |
152 | 0 | size_t Size = R.size(); |
153 | 0 | if (!Size) |
154 | 0 | return *this; |
155 | 0 |
|
156 | 0 | grow(Size); |
157 | 0 | std::memmove(Buffer + Size, Buffer, CurrentPosition); |
158 | 0 | std::memcpy(Buffer, &*R.begin(), Size); |
159 | 0 | CurrentPosition += Size; |
160 | 0 |
|
161 | 0 | notifyInsertion(/*Position=*/0, /*Count=*/Size); |
162 | 0 |
|
163 | 0 | return *this; |
164 | 0 | } |
165 | | |
166 | 0 | OutputBuffer &operator<<(std::string_view R) { return (*this += R); } |
167 | | |
168 | 0 | OutputBuffer &operator<<(char C) { return (*this += C); } |
169 | | |
170 | 0 | OutputBuffer &operator<<(long long N) { |
171 | 0 | return writeUnsigned(static_cast<unsigned long long>(std::abs(N)), N < 0); |
172 | 0 | } |
173 | | |
174 | 0 | OutputBuffer &operator<<(unsigned long long N) { |
175 | 0 | return writeUnsigned(N, false); |
176 | 0 | } |
177 | | |
178 | 0 | OutputBuffer &operator<<(long N) { |
179 | 0 | return this->operator<<(static_cast<long long>(N)); |
180 | 0 | } |
181 | | |
182 | 0 | OutputBuffer &operator<<(unsigned long N) { |
183 | 0 | return this->operator<<(static_cast<unsigned long long>(N)); |
184 | 0 | } |
185 | | |
186 | 0 | OutputBuffer &operator<<(int N) { |
187 | 0 | return this->operator<<(static_cast<long long>(N)); |
188 | 0 | } |
189 | | |
190 | 0 | OutputBuffer &operator<<(unsigned int N) { |
191 | 0 | return this->operator<<(static_cast<unsigned long long>(N)); |
192 | 0 | } |
193 | | |
194 | 0 | void insert(size_t Pos, const char *S, size_t N) { |
195 | 0 | DEMANGLE_ASSERT(Pos <= CurrentPosition, ""); |
196 | 0 | if (N == 0) |
197 | 0 | return; |
198 | 0 |
|
199 | 0 | grow(N); |
200 | 0 | std::memmove(Buffer + Pos + N, Buffer + Pos, CurrentPosition - Pos); |
201 | 0 | std::memcpy(Buffer + Pos, S, N); |
202 | 0 | CurrentPosition += N; |
203 | 0 |
|
204 | 0 | notifyInsertion(Pos, N); |
205 | 0 | } |
206 | | |
207 | 0 | size_t getCurrentPosition() const { return CurrentPosition; } |
208 | 0 | void setCurrentPosition(size_t NewPos) { |
209 | 0 | notifyDeletion(CurrentPosition, NewPos); |
210 | 0 | CurrentPosition = NewPos; |
211 | 0 | } |
212 | | |
213 | 0 | char back() const { |
214 | 0 | DEMANGLE_ASSERT(CurrentPosition, ""); |
215 | 0 | return Buffer[CurrentPosition - 1]; |
216 | 0 | } |
217 | | |
218 | 0 | bool empty() const { return CurrentPosition == 0; } |
219 | | |
220 | 0 | char *getBuffer() { return Buffer; } |
221 | 0 | char *getBufferEnd() { return Buffer + CurrentPosition - 1; } |
222 | 0 | size_t getBufferCapacity() const { return BufferCapacity; } |
223 | | }; |
224 | | |
225 | | template <class T> class ScopedOverride { |
226 | | T &Loc; |
227 | | T Original; |
228 | | |
229 | | public: |
230 | | ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {} |
231 | | |
232 | 3.62k | ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) { |
233 | 3.62k | Loc_ = std::move(NewVal); |
234 | 3.62k | } cxa_demangle.cpp:(anonymous namespace)::itanium_demangle::ScopedOverride<bool>::ScopedOverride(bool&, bool) Line | Count | Source | 232 | 3.46k | ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) { | 233 | 3.46k | Loc_ = std::move(NewVal); | 234 | 3.46k | } |
cxa_demangle.cpp:(anonymous namespace)::itanium_demangle::ScopedOverride<unsigned long>::ScopedOverride(unsigned long&, unsigned long) Line | Count | Source | 232 | 50 | ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) { | 233 | 50 | Loc_ = std::move(NewVal); | 234 | 50 | } |
Unexecuted instantiation: cxa_demangle.cpp:(anonymous namespace)::itanium_demangle::ScopedOverride<unsigned int>::ScopedOverride(unsigned int&, unsigned int) cxa_demangle.cpp:(anonymous namespace)::itanium_demangle::ScopedOverride<char const*>::ScopedOverride(char const*&, char const*) Line | Count | Source | 232 | 106 | ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) { | 233 | 106 | Loc_ = std::move(NewVal); | 234 | 106 | } |
|
235 | 3.62k | ~ScopedOverride() { Loc = std::move(Original); }cxa_demangle.cpp:(anonymous namespace)::itanium_demangle::ScopedOverride<bool>::~ScopedOverride() Line | Count | Source | 235 | 3.46k | ~ScopedOverride() { Loc = std::move(Original); } |
cxa_demangle.cpp:(anonymous namespace)::itanium_demangle::ScopedOverride<unsigned long>::~ScopedOverride() Line | Count | Source | 235 | 50 | ~ScopedOverride() { Loc = std::move(Original); } |
Unexecuted instantiation: cxa_demangle.cpp:(anonymous namespace)::itanium_demangle::ScopedOverride<unsigned int>::~ScopedOverride() cxa_demangle.cpp:(anonymous namespace)::itanium_demangle::ScopedOverride<char const*>::~ScopedOverride() Line | Count | Source | 235 | 106 | ~ScopedOverride() { Loc = std::move(Original); } |
|
236 | | |
237 | | ScopedOverride(const ScopedOverride &) = delete; |
238 | | ScopedOverride &operator=(const ScopedOverride &) = delete; |
239 | | }; |
240 | | |
241 | | DEMANGLE_NAMESPACE_END |
242 | | |
243 | | #endif |