[Clang][CodeGen]`vtable`, `typeinfo` et al. are globals
[llvm-project.git] / libcxxabi / src / demangle / Utility.h
blob8370633aceba5c7b4a1ef7f707c15da9046df404
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.
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.
14 //===----------------------------------------------------------------------===//
16 #ifndef DEMANGLE_UTILITY_H
17 #define DEMANGLE_UTILITY_H
19 #include "DemangleConfig.h"
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>
30 DEMANGLE_NAMESPACE_BEGIN
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;
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();
56 OutputBuffer &writeUnsigned(uint64_t N, bool isNeg = false) {
57 std::array<char, 21> Temp;
58 char *TempPtr = Temp.data() + Temp.size();
60 // Output at least one character.
61 do {
62 *--TempPtr = char('0' + N % 10);
63 N /= 10;
64 } while (N);
66 // Add negative sign.
67 if (isNeg)
68 *--TempPtr = '-';
70 return operator+=(
71 std::string_view(TempPtr, Temp.data() + Temp.size() - TempPtr));
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;
84 operator std::string_view() const {
85 return std::string_view(Buffer, CurrentPosition);
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();
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;
97 bool isGtInsideTemplateArgs() const { return GtIsGt == 0; }
99 void printOpen(char Open = '(') {
100 GtIsGt++;
101 *this += Open;
103 void printClose(char Close = ')') {
104 GtIsGt--;
105 *this += Close;
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;
114 return *this;
117 OutputBuffer &operator+=(char C) {
118 grow(1);
119 Buffer[CurrentPosition++] = C;
120 return *this;
123 OutputBuffer &prepend(std::string_view R) {
124 size_t Size = R.size();
126 grow(Size);
127 std::memmove(Buffer + Size, Buffer, CurrentPosition);
128 std::memcpy(Buffer, &*R.begin(), Size);
129 CurrentPosition += Size;
131 return *this;
134 OutputBuffer &operator<<(std::string_view R) { return (*this += R); }
136 OutputBuffer &operator<<(char C) { return (*this += C); }
138 OutputBuffer &operator<<(long long N) {
139 return writeUnsigned(static_cast<unsigned long long>(std::abs(N)), N < 0);
142 OutputBuffer &operator<<(unsigned long long N) {
143 return writeUnsigned(N, false);
146 OutputBuffer &operator<<(long N) {
147 return this->operator<<(static_cast<long long>(N));
150 OutputBuffer &operator<<(unsigned long N) {
151 return this->operator<<(static_cast<unsigned long long>(N));
154 OutputBuffer &operator<<(int N) {
155 return this->operator<<(static_cast<long long>(N));
158 OutputBuffer &operator<<(unsigned int N) {
159 return this->operator<<(static_cast<unsigned long long>(N));
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;
172 size_t getCurrentPosition() const { return CurrentPosition; }
173 void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
175 char back() const {
176 assert(CurrentPosition);
177 return Buffer[CurrentPosition - 1];
180 bool empty() const { return CurrentPosition == 0; }
182 char *getBuffer() { return Buffer; }
183 char *getBufferEnd() { return Buffer + CurrentPosition - 1; }
184 size_t getBufferCapacity() const { return BufferCapacity; }
187 template <class T> class ScopedOverride {
188 T &Loc;
189 T Original;
191 public:
192 ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {}
194 ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) {
195 Loc_ = std::move(NewVal);
197 ~ScopedOverride() { Loc = std::move(Original); }
199 ScopedOverride(const ScopedOverride &) = delete;
200 ScopedOverride &operator=(const ScopedOverride &) = delete;
203 DEMANGLE_NAMESPACE_END
205 #endif