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