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