Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
emscripten-core
GitHub Repository: emscripten-core/emscripten
Path: blob/main/system/lib/libcxxabi/src/demangle/Utility.h
6174 views
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
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:
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;
82
OutputBuffer &operator=(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
131
OutputBuffer &operator+=(char C) {
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
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
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
211
template <class T> class ScopedOverride {
212
T &Loc;
213
T Original;
214
215
public:
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
223
ScopedOverride(const ScopedOverride &) = delete;
224
ScopedOverride &operator=(const ScopedOverride &) = delete;
225
};
226
227
DEMANGLE_NAMESPACE_END
228
229
#endif
230
231