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