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