blob: da4a0c050bc5c5b54f3d8052a806c6b8807552fb [file] [log] [blame]
Andrew Scull0372a572018-11-16 15:47:06 +00001//===--- 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.
25class OutputStream {
26 char *Buffer;
27 size_t CurrentPosition;
28 size_t BufferCapacity;
29
30 // Ensure there is at least n more positions in buffer.
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
63public:
64 OutputStream(char *StartBuf, size_t Size)
65 : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {}
66 OutputStream() = default;
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
127 size_t getCurrentPosition() const { return CurrentPosition; }
128 void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
129
130 char back() const {
131 return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0';
132 }
133
134 bool empty() const { return CurrentPosition == 0; }
135
136 char *getBuffer() { return Buffer; }
137 char *getBufferEnd() { return Buffer + CurrentPosition - 1; }
138 size_t getBufferCapacity() { return BufferCapacity; }
139};
140
141template <class T> class SwapAndRestore {
142 T &Restore;
143 T OriginalValue;
144 bool ShouldRestore = true;
145
146public:
147 SwapAndRestore(T &Restore_) : SwapAndRestore(Restore_, Restore_) {}
148
149 SwapAndRestore(T &Restore_, T NewVal)
150 : Restore(Restore_), OriginalValue(Restore) {
151 Restore = std::move(NewVal);
152 }
153 ~SwapAndRestore() {
154 if (ShouldRestore)
155 Restore = std::move(OriginalValue);
156 }
157
158 void shouldRestore(bool ShouldRestore_) { ShouldRestore = ShouldRestore_; }
159
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
172inline 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 true;
179 BufferSize = InitSize;
180 } else
181 BufferSize = *N;
182
183 S.reset(Buf, BufferSize);
184 return false;
185}
186
187#endif