1 //===--- Utility.h ----------------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
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.
14 //===----------------------------------------------------------------------===//
16 #ifndef DEMANGLE_UTILITY_H
17 #define DEMANGLE_UTILITY_H
19 #include "DemangleConfig.h"
26 #include <string_view>
28 DEMANGLE_NAMESPACE_BEGIN
30 // Stream that AST nodes write their string representation into after the AST
33 char *Buffer
= nullptr;
34 size_t CurrentPosition
= 0;
35 size_t BufferCapacity
= 0;
37 // Ensure there are at least N more positions in the buffer.
39 size_t Need
= N
+ CurrentPosition
;
40 if (Need
> BufferCapacity
) {
41 // Reduce the number of reallocations, with a bit of hysteresis. The
42 // number here is chosen so the first allocation will more-than-likely not
43 // allocate more than 1K.
46 if (BufferCapacity
< Need
)
47 BufferCapacity
= Need
;
48 Buffer
= static_cast<char *>(std::realloc(Buffer
, BufferCapacity
));
49 if (Buffer
== nullptr)
54 OutputBuffer
&writeUnsigned(uint64_t N
, bool isNeg
= false) {
55 std::array
<char, 21> Temp
;
56 char *TempPtr
= Temp
.data() + Temp
.size();
58 // Output at least one character.
60 *--TempPtr
= char('0' + N
% 10);
69 std::string_view(TempPtr
, Temp
.data() + Temp
.size() - TempPtr
));
73 OutputBuffer(char *StartBuf
, size_t Size
)
74 : Buffer(StartBuf
), BufferCapacity(Size
) {}
75 OutputBuffer(char *StartBuf
, size_t *SizePtr
)
76 : OutputBuffer(StartBuf
, StartBuf
? *SizePtr
: 0) {}
77 OutputBuffer() = default;
79 OutputBuffer(const OutputBuffer
&) = delete;
80 OutputBuffer
&operator=(const OutputBuffer
&) = delete;
82 operator std::string_view() const {
83 return std::string_view(Buffer
, CurrentPosition
);
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();
91 /// When zero, we're printing template args and '>' needs to be parenthesized.
92 /// Use a counter so we can simply increment inside parentheses.
95 bool isGtInsideTemplateArgs() const { return GtIsGt
== 0; }
97 void printOpen(char Open
= '(') {
101 void printClose(char Close
= ')') {
106 OutputBuffer
&operator+=(std::string_view R
) {
107 if (size_t Size
= R
.size()) {
109 std::memcpy(Buffer
+ CurrentPosition
, &*R
.begin(), Size
);
110 CurrentPosition
+= Size
;
115 OutputBuffer
&operator+=(char C
) {
117 Buffer
[CurrentPosition
++] = C
;
121 OutputBuffer
&prepend(std::string_view R
) {
122 size_t Size
= R
.size();
125 std::memmove(Buffer
+ Size
, Buffer
, CurrentPosition
);
126 std::memcpy(Buffer
, &*R
.begin(), Size
);
127 CurrentPosition
+= Size
;
132 OutputBuffer
&operator<<(std::string_view R
) { return (*this += R
); }
134 OutputBuffer
&operator<<(char C
) { return (*this += C
); }
136 OutputBuffer
&operator<<(long long N
) {
137 return writeUnsigned(static_cast<unsigned long long>(std::abs(N
)), N
< 0);
140 OutputBuffer
&operator<<(unsigned long long N
) {
141 return writeUnsigned(N
, false);
144 OutputBuffer
&operator<<(long N
) {
145 return this->operator<<(static_cast<long long>(N
));
148 OutputBuffer
&operator<<(unsigned long N
) {
149 return this->operator<<(static_cast<unsigned long long>(N
));
152 OutputBuffer
&operator<<(int N
) {
153 return this->operator<<(static_cast<long long>(N
));
156 OutputBuffer
&operator<<(unsigned int N
) {
157 return this->operator<<(static_cast<unsigned long long>(N
));
160 void insert(size_t Pos
, const char *S
, size_t N
) {
161 DEMANGLE_ASSERT(Pos
<= CurrentPosition
, "");
165 std::memmove(Buffer
+ Pos
+ N
, Buffer
+ Pos
, CurrentPosition
- Pos
);
166 std::memcpy(Buffer
+ Pos
, S
, N
);
167 CurrentPosition
+= N
;
170 size_t getCurrentPosition() const { return CurrentPosition
; }
171 void setCurrentPosition(size_t NewPos
) { CurrentPosition
= NewPos
; }
174 DEMANGLE_ASSERT(CurrentPosition
, "");
175 return Buffer
[CurrentPosition
- 1];
178 bool empty() const { return CurrentPosition
== 0; }
180 char *getBuffer() { return Buffer
; }
181 char *getBufferEnd() { return Buffer
+ CurrentPosition
- 1; }
182 size_t getBufferCapacity() const { return BufferCapacity
; }
185 template <class T
> class ScopedOverride
{
190 ScopedOverride(T
&Loc_
) : ScopedOverride(Loc_
, Loc_
) {}
192 ScopedOverride(T
&Loc_
, T NewVal
) : Loc(Loc_
), Original(Loc_
) {
193 Loc_
= std::move(NewVal
);
195 ~ScopedOverride() { Loc
= std::move(Original
); }
197 ScopedOverride(const ScopedOverride
&) = delete;
198 ScopedOverride
&operator=(const ScopedOverride
&) = delete;
201 DEMANGLE_NAMESPACE_END