xref: /freebsd/contrib/llvm-project/llvm/include/llvm/Demangle/Utility.h (revision 725a9f47324d42037db93c27ceb40d4956872f3e)
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 "DemangleConfig.h"
20 
21 #include <array>
22 #include <cstdint>
23 #include <cstdlib>
24 #include <cstring>
25 #include <limits>
26 #include <string_view>
27 
28 DEMANGLE_NAMESPACE_BEGIN
29 
30 // Stream that AST nodes write their string representation into after the AST
31 // has been parsed.
32 class OutputBuffer {
33   char *Buffer = nullptr;
34   size_t CurrentPosition = 0;
35   size_t BufferCapacity = 0;
36 
37   // Ensure there are at least N more positions in the buffer.
38   void grow(size_t N) {
39     size_t Need = N + CurrentPosition;
40     if (Need > BufferCapacity) {
41       // Reduce the number of reallocations, with a bit of hysteresis. The
42       // number here is chosen so the first allocation will more-than-likely not
43       // allocate more than 1K.
44       Need += 1024 - 32;
45       BufferCapacity *= 2;
46       if (BufferCapacity < Need)
47         BufferCapacity = Need;
48       Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));
49       if (Buffer == nullptr)
50         std::abort();
51     }
52   }
53 
54   OutputBuffer &writeUnsigned(uint64_t N, bool isNeg = false) {
55     std::array<char, 21> Temp;
56     char *TempPtr = Temp.data() + Temp.size();
57 
58     // Output at least one character.
59     do {
60       *--TempPtr = char('0' + N % 10);
61       N /= 10;
62     } while (N);
63 
64     // Add negative sign.
65     if (isNeg)
66       *--TempPtr = '-';
67 
68     return operator+=(
69         std::string_view(TempPtr, Temp.data() + Temp.size() - TempPtr));
70   }
71 
72 public:
73   OutputBuffer(char *StartBuf, size_t Size)
74       : Buffer(StartBuf), BufferCapacity(Size) {}
75   OutputBuffer(char *StartBuf, size_t *SizePtr)
76       : OutputBuffer(StartBuf, StartBuf ? *SizePtr : 0) {}
77   OutputBuffer() = default;
78   // Non-copyable
79   OutputBuffer(const OutputBuffer &) = delete;
80   OutputBuffer &operator=(const OutputBuffer &) = delete;
81 
82   operator std::string_view() const {
83     return std::string_view(Buffer, CurrentPosition);
84   }
85 
86   /// If a ParameterPackExpansion (or similar type) is encountered, the offset
87   /// into the pack that we're currently printing.
88   unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
89   unsigned CurrentPackMax = std::numeric_limits<unsigned>::max();
90 
91   /// When zero, we're printing template args and '>' needs to be parenthesized.
92   /// Use a counter so we can simply increment inside parentheses.
93   unsigned GtIsGt = 1;
94 
95   bool isGtInsideTemplateArgs() const { return GtIsGt == 0; }
96 
97   void printOpen(char Open = '(') {
98     GtIsGt++;
99     *this += Open;
100   }
101   void printClose(char Close = ')') {
102     GtIsGt--;
103     *this += Close;
104   }
105 
106   OutputBuffer &operator+=(std::string_view R) {
107     if (size_t Size = R.size()) {
108       grow(Size);
109       std::memcpy(Buffer + CurrentPosition, &*R.begin(), Size);
110       CurrentPosition += Size;
111     }
112     return *this;
113   }
114 
115   OutputBuffer &operator+=(char C) {
116     grow(1);
117     Buffer[CurrentPosition++] = C;
118     return *this;
119   }
120 
121   OutputBuffer &prepend(std::string_view R) {
122     size_t Size = R.size();
123 
124     grow(Size);
125     std::memmove(Buffer + Size, Buffer, CurrentPosition);
126     std::memcpy(Buffer, &*R.begin(), Size);
127     CurrentPosition += Size;
128 
129     return *this;
130   }
131 
132   OutputBuffer &operator<<(std::string_view R) { return (*this += R); }
133 
134   OutputBuffer &operator<<(char C) { return (*this += C); }
135 
136   OutputBuffer &operator<<(long long N) {
137     return writeUnsigned(static_cast<unsigned long long>(std::abs(N)), N < 0);
138   }
139 
140   OutputBuffer &operator<<(unsigned long long N) {
141     return writeUnsigned(N, false);
142   }
143 
144   OutputBuffer &operator<<(long N) {
145     return this->operator<<(static_cast<long long>(N));
146   }
147 
148   OutputBuffer &operator<<(unsigned long N) {
149     return this->operator<<(static_cast<unsigned long long>(N));
150   }
151 
152   OutputBuffer &operator<<(int N) {
153     return this->operator<<(static_cast<long long>(N));
154   }
155 
156   OutputBuffer &operator<<(unsigned int N) {
157     return this->operator<<(static_cast<unsigned long long>(N));
158   }
159 
160   void insert(size_t Pos, const char *S, size_t N) {
161     DEMANGLE_ASSERT(Pos <= CurrentPosition, "");
162     if (N == 0)
163       return;
164     grow(N);
165     std::memmove(Buffer + Pos + N, Buffer + Pos, CurrentPosition - Pos);
166     std::memcpy(Buffer + Pos, S, N);
167     CurrentPosition += N;
168   }
169 
170   size_t getCurrentPosition() const { return CurrentPosition; }
171   void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
172 
173   char back() const {
174     DEMANGLE_ASSERT(CurrentPosition, "");
175     return Buffer[CurrentPosition - 1];
176   }
177 
178   bool empty() const { return CurrentPosition == 0; }
179 
180   char *getBuffer() { return Buffer; }
181   char *getBufferEnd() { return Buffer + CurrentPosition - 1; }
182   size_t getBufferCapacity() const { return BufferCapacity; }
183 };
184 
185 template <class T> class ScopedOverride {
186   T &Loc;
187   T Original;
188 
189 public:
190   ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {}
191 
192   ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) {
193     Loc_ = std::move(NewVal);
194   }
195   ~ScopedOverride() { Loc = std::move(Original); }
196 
197   ScopedOverride(const ScopedOverride &) = delete;
198   ScopedOverride &operator=(const ScopedOverride &) = delete;
199 };
200 
201 DEMANGLE_NAMESPACE_END
202 
203 #endif
204