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