• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===--- Utility.h ----------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //
9 // This file contains several utility classes used by the demangle library.
10 //===----------------------------------------------------------------------===//
11 
12 #ifndef LLVM_DEMANGLE_UTILITY_H
13 #define LLVM_DEMANGLE_UTILITY_H
14 
15 #include "StringView.h"
16 
17 #include <cstdint>
18 #include <cstdlib>
19 #include <cstring>
20 #include <iterator>
21 #include <limits>
22 
23 // Stream that AST nodes write their string representation into after the AST
24 // has been parsed.
25 class OutputStream {
26   char *Buffer;
27   size_t CurrentPosition;
28   size_t BufferCapacity;
29 
30   // Ensure there is at least n more positions in buffer.
grow(size_t N)31   void grow(size_t N) {
32     if (N + CurrentPosition >= BufferCapacity) {
33       BufferCapacity *= 2;
34       if (BufferCapacity < N + CurrentPosition)
35         BufferCapacity = N + CurrentPosition;
36       Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));
37       if (Buffer == nullptr)
38         std::terminate();
39     }
40   }
41 
42   void writeUnsigned(uint64_t N, bool isNeg = false) {
43     // Handle special case...
44     if (N == 0) {
45       *this << '0';
46       return;
47     }
48 
49     char Temp[21];
50     char *TempPtr = std::end(Temp);
51 
52     while (N) {
53       *--TempPtr = '0' + char(N % 10);
54       N /= 10;
55     }
56 
57     // Add negative sign...
58     if (isNeg)
59       *--TempPtr = '-';
60     this->operator<<(StringView(TempPtr, std::end(Temp)));
61   }
62 
63 public:
OutputStream(char * StartBuf,size_t Size)64   OutputStream(char *StartBuf, size_t Size)
65       : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {}
66   OutputStream() = default;
reset(char * Buffer_,size_t BufferCapacity_)67   void reset(char *Buffer_, size_t BufferCapacity_) {
68     CurrentPosition = 0;
69     Buffer = Buffer_;
70     BufferCapacity = BufferCapacity_;
71   }
72 
73   /// Create an OutputStream from a buffer and a size.  If either of these are
74   /// null a buffer is allocated.
create(char * StartBuf,size_t * Size,size_t AllocSize)75   static OutputStream create(char *StartBuf, size_t *Size, size_t AllocSize) {
76     OutputStream Result;
77 
78     if (!StartBuf || !Size) {
79       StartBuf = static_cast<char *>(std::malloc(AllocSize));
80       if (StartBuf == nullptr)
81         std::terminate();
82       Size = &AllocSize;
83     }
84 
85     Result.reset(StartBuf, *Size);
86     return Result;
87   }
88 
89   /// If a ParameterPackExpansion (or similar type) is encountered, the offset
90   /// into the pack that we're currently printing.
91   unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
92   unsigned CurrentPackMax = std::numeric_limits<unsigned>::max();
93 
94   OutputStream &operator+=(StringView R) {
95     size_t Size = R.size();
96     if (Size == 0)
97       return *this;
98     grow(Size);
99     std::memmove(Buffer + CurrentPosition, R.begin(), Size);
100     CurrentPosition += Size;
101     return *this;
102   }
103 
104   OutputStream &operator+=(char C) {
105     grow(1);
106     Buffer[CurrentPosition++] = C;
107     return *this;
108   }
109 
110   OutputStream &operator<<(StringView R) { return (*this += R); }
111 
112   OutputStream &operator<<(char C) { return (*this += C); }
113 
114   OutputStream &operator<<(long long N) {
115     if (N < 0)
116       writeUnsigned(static_cast<unsigned long long>(-N), true);
117     else
118       writeUnsigned(static_cast<unsigned long long>(N));
119     return *this;
120   }
121 
122   OutputStream &operator<<(unsigned long long N) {
123     writeUnsigned(N, false);
124     return *this;
125   }
126 
127   OutputStream &operator<<(long N) {
128     return this->operator<<(static_cast<long long>(N));
129   }
130 
131   OutputStream &operator<<(unsigned long N) {
132     return this->operator<<(static_cast<unsigned long long>(N));
133   }
134 
135   OutputStream &operator<<(int N) {
136     return this->operator<<(static_cast<long long>(N));
137   }
138 
139   OutputStream &operator<<(unsigned int N) {
140     return this->operator<<(static_cast<unsigned long long>(N));
141   }
142 
getCurrentPosition()143   size_t getCurrentPosition() const { return CurrentPosition; }
setCurrentPosition(size_t NewPos)144   void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
145 
back()146   char back() const {
147     return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0';
148   }
149 
empty()150   bool empty() const { return CurrentPosition == 0; }
151 
getBuffer()152   char *getBuffer() { return Buffer; }
getBufferEnd()153   char *getBufferEnd() { return Buffer + CurrentPosition - 1; }
getBufferCapacity()154   size_t getBufferCapacity() { return BufferCapacity; }
155 };
156 
157 template <class T> class SwapAndRestore {
158   T &Restore;
159   T OriginalValue;
160   bool ShouldRestore = true;
161 
162 public:
SwapAndRestore(T & Restore_)163   SwapAndRestore(T &Restore_) : SwapAndRestore(Restore_, Restore_) {}
164 
SwapAndRestore(T & Restore_,T NewVal)165   SwapAndRestore(T &Restore_, T NewVal)
166       : Restore(Restore_), OriginalValue(Restore) {
167     Restore = std::move(NewVal);
168   }
~SwapAndRestore()169   ~SwapAndRestore() {
170     if (ShouldRestore)
171       Restore = std::move(OriginalValue);
172   }
173 
shouldRestore(bool ShouldRestore_)174   void shouldRestore(bool ShouldRestore_) { ShouldRestore = ShouldRestore_; }
175 
restoreNow(bool Force)176   void restoreNow(bool Force) {
177     if (!Force && !ShouldRestore)
178       return;
179 
180     Restore = std::move(OriginalValue);
181     ShouldRestore = false;
182   }
183 
184   SwapAndRestore(const SwapAndRestore &) = delete;
185   SwapAndRestore &operator=(const SwapAndRestore &) = delete;
186 };
187 
188 #endif
189