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