LLVM 22.0.0git
Utility.h
Go to the documentation of this file.
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
29
30class Node;
31
32// Stream that AST nodes write their string representation into after the AST
33// has been parsed.
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 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
74public:
75 OutputBuffer(char *StartBuf, size_t Size)
76 : Buffer(StartBuf), BufferCapacity(Size) {}
77 OutputBuffer(char *StartBuf, size_t *SizePtr)
78 : OutputBuffer(StartBuf, StartBuf ? *SizePtr : 0) {}
79 OutputBuffer() = default;
80 // Non-copyable
81 OutputBuffer(const OutputBuffer &) = delete;
83
84 virtual ~OutputBuffer() {}
85
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.
97 virtual void notifyInsertion(size_t /*Position*/, size_t /*Count*/) {}
98
99 /// Called when we make the \c CurrentPosition of this object smaller.
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
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
132 grow(1);
133 Buffer[CurrentPosition++] = C;
134 return *this;
135 }
136
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
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
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
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
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
193 size_t getCurrentPosition() const { return CurrentPosition; }
194 void setCurrentPosition(size_t NewPos) {
195 notifyDeletion(CurrentPosition, NewPos);
196 CurrentPosition = NewPos;
197 }
198
199 char back() const {
200 DEMANGLE_ASSERT(CurrentPosition, "");
201 return Buffer[CurrentPosition - 1];
202 }
203
204 bool empty() const { return CurrentPosition == 0; }
205
206 char *getBuffer() { return Buffer; }
207 char *getBufferEnd() { return Buffer + CurrentPosition - 1; }
208 size_t getBufferCapacity() const { return BufferCapacity; }
209};
210
211template <class T> class ScopedOverride {
212 T &Loc;
213 T Original;
214
215public:
216 ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {}
217
218 ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) {
219 Loc_ = std::move(NewVal);
220 }
221 ~ScopedOverride() { Loc = std::move(Original); }
222
225};
226
228
229#endif
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static bool isNeg(Value *V)
Returns true if the operation is a negation of V, and it works for both integers and floats.
#define DEMANGLE_NAMESPACE_END
#define DEMANGLE_ASSERT(__expr, __msg)
#define DEMANGLE_NAMESPACE_BEGIN
uint64_t Size
char * getBufferEnd()
Definition: Utility.h:207
OutputBuffer & operator<<(unsigned long long N)
Definition: Utility.h:160
OutputBuffer()=default
OutputBuffer(const OutputBuffer &)=delete
size_t getBufferCapacity() const
Definition: Utility.h:208
OutputBuffer & operator+=(std::string_view R)
Definition: Utility.h:122
bool empty() const
Definition: Utility.h:204
virtual void printRight(const Node &N)
OutputBuffer(char *StartBuf, size_t Size)
Definition: Utility.h:75
unsigned GtIsGt
When zero, we're printing template args and '>' needs to be parenthesized.
Definition: Utility.h:109
virtual void printLeft(const Node &N)
Called by the demangler when printing the demangle tree.
OutputBuffer(char *StartBuf, size_t *SizePtr)
Definition: Utility.h:77
OutputBuffer & operator<<(char C)
Definition: Utility.h:154
char back() const
Definition: Utility.h:199
OutputBuffer & operator=(const OutputBuffer &)=delete
virtual void notifyInsertion(size_t, size_t)
Called when we write to this object anywhere other than the end.
Definition: Utility.h:97
OutputBuffer & prepend(std::string_view R)
Definition: Utility.h:137
char * getBuffer()
Definition: Utility.h:206
unsigned CurrentPackMax
Definition: Utility.h:105
OutputBuffer & operator<<(std::string_view R)
Definition: Utility.h:152
unsigned CurrentPackIndex
If a ParameterPackExpansion (or similar type) is encountered, the offset into the pack that we're cur...
Definition: Utility.h:104
virtual ~OutputBuffer()
Definition: Utility.h:84
OutputBuffer & operator<<(long N)
Definition: Utility.h:164
OutputBuffer & operator<<(int N)
Definition: Utility.h:172
OutputBuffer & operator<<(long long N)
Definition: Utility.h:156
virtual void notifyDeletion(size_t, size_t)
Called when we make the CurrentPosition of this object smaller.
Definition: Utility.h:100
void printClose(char Close=')')
Definition: Utility.h:117
void setCurrentPosition(size_t NewPos)
Definition: Utility.h:194
bool isGtInsideTemplateArgs() const
Definition: Utility.h:111
OutputBuffer & operator+=(char C)
Definition: Utility.h:131
size_t getCurrentPosition() const
Definition: Utility.h:193
void printOpen(char Open='(')
Definition: Utility.h:113
void insert(size_t Pos, const char *S, size_t N)
Definition: Utility.h:180
OutputBuffer & operator<<(unsigned long N)
Definition: Utility.h:168
OutputBuffer & operator<<(unsigned int N)
Definition: Utility.h:176
ScopedOverride(T &Loc_, T NewVal)
Definition: Utility.h:218
ScopedOverride(T &Loc_)
Definition: Utility.h:216
ScopedOverride & operator=(const ScopedOverride &)=delete
ScopedOverride(const ScopedOverride &)=delete
#define N