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(s). |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #ifndef DEMANGLE_UTILITY_H |
14 | #define DEMANGLE_UTILITY_H |
15 | |
16 | #include "StringView.h" |
17 | #include <cstdint> |
18 | #include <cstdlib> |
19 | #include <cstring> |
20 | #include <iterator> |
21 | #include <limits> |
22 | |
23 | DEMANGLE_NAMESPACE_BEGIN |
24 | |
25 | // Stream that AST nodes write their string representation into after the AST |
26 | // has been parsed. |
27 | class OutputStream { |
28 | char *Buffer; |
29 | size_t CurrentPosition; |
30 | size_t BufferCapacity; |
31 | |
32 | // Ensure there is at least n more positions in buffer. |
33 | void grow(size_t N) { |
34 | if (N + CurrentPosition >= BufferCapacity) { |
35 | BufferCapacity *= 2; |
36 | if (BufferCapacity < N + CurrentPosition) |
37 | BufferCapacity = N + CurrentPosition; |
38 | Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity)); |
39 | if (Buffer == nullptr) |
40 | std::terminate(); |
41 | } |
42 | } |
43 | |
44 | void writeUnsigned(uint64_t N, bool isNeg = false) { |
45 | // Handle special case... |
46 | if (N == 0) { |
47 | *this << '0'; |
48 | return; |
49 | } |
50 | |
51 | char Temp[21]; |
52 | char *TempPtr = std::end(Temp); |
53 | |
54 | while (N) { |
55 | *--TempPtr = '0' + char(N % 10); |
56 | N /= 10; |
57 | } |
58 | |
59 | // Add negative sign... |
60 | if (isNeg) |
61 | *--TempPtr = '-'; |
62 | this->operator<<(StringView(TempPtr, std::end(Temp))); |
63 | } |
64 | |
65 | public: |
66 | OutputStream(char *StartBuf, size_t Size) |
67 | : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {} |
68 | OutputStream() = default; |
69 | void reset(char *Buffer_, size_t BufferCapacity_) { |
70 | CurrentPosition = 0; |
71 | Buffer = Buffer_; |
72 | BufferCapacity = BufferCapacity_; |
73 | } |
74 | |
75 | /// If a ParameterPackExpansion (or similar type) is encountered, the offset |
76 | /// into the pack that we're currently printing. |
77 | unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max(); |
78 | unsigned CurrentPackMax = std::numeric_limits<unsigned>::max(); |
79 | |
80 | OutputStream &operator+=(StringView R) { |
81 | size_t Size = R.size(); |
82 | if (Size == 0) |
83 | return *this; |
84 | grow(Size); |
85 | std::memmove(Buffer + CurrentPosition, R.begin(), Size); |
86 | CurrentPosition += Size; |
87 | return *this; |
88 | } |
89 | |
90 | OutputStream &operator+=(char C) { |
91 | grow(1); |
92 | Buffer[CurrentPosition++] = C; |
93 | return *this; |
94 | } |
95 | |
96 | OutputStream &operator<<(StringView R) { return (*this += R); } |
97 | |
98 | OutputStream &operator<<(char C) { return (*this += C); } |
99 | |
100 | OutputStream &operator<<(long long N) { |
101 | if (N < 0) |
102 | writeUnsigned(static_cast<unsigned long long>(-N), true); |
103 | else |
104 | writeUnsigned(static_cast<unsigned long long>(N)); |
105 | return *this; |
106 | } |
107 | |
108 | OutputStream &operator<<(unsigned long long N) { |
109 | writeUnsigned(N, false); |
110 | return *this; |
111 | } |
112 | |
113 | OutputStream &operator<<(long N) { |
114 | return this->operator<<(static_cast<long long>(N)); |
115 | } |
116 | |
117 | OutputStream &operator<<(unsigned long N) { |
118 | return this->operator<<(static_cast<unsigned long long>(N)); |
119 | } |
120 | |
121 | OutputStream &operator<<(int N) { |
122 | return this->operator<<(static_cast<long long>(N)); |
123 | } |
124 | |
125 | OutputStream &operator<<(unsigned int N) { |
126 | return this->operator<<(static_cast<unsigned long long>(N)); |
127 | } |
128 | |
129 | size_t getCurrentPosition() const { return CurrentPosition; } |
130 | void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; } |
131 | |
132 | char back() const { |
133 | return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0'; |
134 | } |
135 | |
136 | bool empty() const { return CurrentPosition == 0; } |
137 | |
138 | char *getBuffer() { return Buffer; } |
139 | char *getBufferEnd() { return Buffer + CurrentPosition - 1; } |
140 | size_t getBufferCapacity() { return BufferCapacity; } |
141 | }; |
142 | |
143 | template <class T> class SwapAndRestore { |
144 | T &Restore; |
145 | T OriginalValue; |
146 | bool ShouldRestore = true; |
147 | |
148 | public: |
149 | SwapAndRestore(T &Restore_) : SwapAndRestore(Restore_, Restore_) {} |
150 | |
151 | SwapAndRestore(T &Restore_, T NewVal) |
152 | : Restore(Restore_), OriginalValue(Restore) { |
153 | Restore = std::move(NewVal); |
154 | } |
155 | ~SwapAndRestore() { |
156 | if (ShouldRestore) |
157 | Restore = std::move(OriginalValue); |
158 | } |
159 | |
160 | void shouldRestore(bool ShouldRestore_) { ShouldRestore = ShouldRestore_; } |
161 | |
162 | void restoreNow(bool Force) { |
163 | if (!Force && !ShouldRestore) |
164 | return; |
165 | |
166 | Restore = std::move(OriginalValue); |
167 | ShouldRestore = false; |
168 | } |
169 | |
170 | SwapAndRestore(const SwapAndRestore &) = delete; |
171 | SwapAndRestore &operator=(const SwapAndRestore &) = delete; |
172 | }; |
173 | |
174 | inline bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S, |
175 | size_t InitSize) { |
176 | size_t BufferSize; |
177 | if (Buf == nullptr) { |
178 | Buf = static_cast<char *>(std::malloc(InitSize)); |
179 | if (Buf == nullptr) |
180 | return false; |
181 | BufferSize = InitSize; |
182 | } else |
183 | BufferSize = *N; |
184 | |
185 | S.reset(Buf, BufferSize); |
186 | return true; |
187 | } |
188 | |
189 | DEMANGLE_NAMESPACE_END |
190 | |
191 | #endif |
192 | |