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