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