brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.9 KiB · df5b54d Raw
244 lines · c
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-exception6//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 libcxxabi11// is the original and the one in llvm is the copy.  Use cp-to-llvm.sh to update12// the copy.  See README.txt for more details.13//14//===----------------------------------------------------------------------===//15 16#ifndef DEMANGLE_UTILITY_H17#define DEMANGLE_UTILITY_H18 19#include "DemangleConfig.h"20 21#include <array>22#include <cstdint>23#include <cstdlib>24#include <cstring>25#include <limits>26#include <string_view>27 28DEMANGLE_NAMESPACE_BEGIN29 30class Node;31 32// Stream that AST nodes write their string representation into after the AST33// has been parsed.34class 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. The44      // number here is chosen so the first allocation will more-than-likely not45      // 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::abort();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 74public: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-copyable81  OutputBuffer(const OutputBuffer &) = delete;82  OutputBuffer &operator=(const OutputBuffer &) = delete;83 84  virtual ~OutputBuffer() = default;85 86  operator std::string_view() const {87    return std::string_view(Buffer, CurrentPosition);88  }89 90  /// Called by the demangler when printing the demangle tree. By91  /// default calls into \c Node::print{Left|Right} but can be overriden92  /// by clients to track additional state when printing the demangled name.93  virtual void printLeft(const Node &N);94  virtual void printRight(const Node &N);95 96  /// Called when we write to this object anywhere other than the end.97  virtual void notifyInsertion(size_t /*Position*/, size_t /*Count*/) {}98 99  /// Called when we make the \c CurrentPosition of this object smaller.100  virtual void notifyDeletion(size_t /*OldPos*/, size_t /*NewPos*/) {}101 102  /// If a ParameterPackExpansion (or similar type) is encountered, the offset103  /// into the pack that we're currently printing.104  unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();105  unsigned CurrentPackMax = std::numeric_limits<unsigned>::max();106 107  struct {108    /// The depth of '(' and ')' inside the currently printed template109    /// arguments.110    unsigned ParenDepth = 0;111 112    /// True if we're currently printing a template argument.113    bool InsideTemplate = false;114  } TemplateTracker;115 116  /// Returns true if we're currently between a '(' and ')' when printing117  /// template args.118  bool isInParensInTemplateArgs() const {119    return TemplateTracker.ParenDepth > 0;120  }121 122  /// Returns true if we're printing template args.123  bool isInsideTemplateArgs() const { return TemplateTracker.InsideTemplate; }124 125  void printOpen(char Open = '(') {126    if (isInsideTemplateArgs())127      TemplateTracker.ParenDepth++;128    *this += Open;129  }130  void printClose(char Close = ')') {131    if (isInsideTemplateArgs())132      TemplateTracker.ParenDepth--;133    *this += Close;134  }135 136  OutputBuffer &operator+=(std::string_view R) {137    if (size_t Size = R.size()) {138      grow(Size);139      std::memcpy(Buffer + CurrentPosition, &*R.begin(), Size);140      CurrentPosition += Size;141    }142    return *this;143  }144 145  OutputBuffer &operator+=(char C) {146    grow(1);147    Buffer[CurrentPosition++] = C;148    return *this;149  }150 151  OutputBuffer &prepend(std::string_view R) {152    size_t Size = R.size();153    if (!Size)154      return *this;155 156    grow(Size);157    std::memmove(Buffer + Size, Buffer, CurrentPosition);158    std::memcpy(Buffer, &*R.begin(), Size);159    CurrentPosition += Size;160 161    notifyInsertion(/*Position=*/0, /*Count=*/Size);162 163    return *this;164  }165 166  OutputBuffer &operator<<(std::string_view R) { return (*this += R); }167 168  OutputBuffer &operator<<(char C) { return (*this += C); }169 170  OutputBuffer &operator<<(long long N) {171    return writeUnsigned(static_cast<unsigned long long>(std::abs(N)), N < 0);172  }173 174  OutputBuffer &operator<<(unsigned long long N) {175    return writeUnsigned(N, false);176  }177 178  OutputBuffer &operator<<(long N) {179    return this->operator<<(static_cast<long long>(N));180  }181 182  OutputBuffer &operator<<(unsigned long N) {183    return this->operator<<(static_cast<unsigned long long>(N));184  }185 186  OutputBuffer &operator<<(int N) {187    return this->operator<<(static_cast<long long>(N));188  }189 190  OutputBuffer &operator<<(unsigned int N) {191    return this->operator<<(static_cast<unsigned long long>(N));192  }193 194  void insert(size_t Pos, const char *S, size_t N) {195    DEMANGLE_ASSERT(Pos <= CurrentPosition, "");196    if (N == 0)197      return;198 199    grow(N);200    std::memmove(Buffer + Pos + N, Buffer + Pos, CurrentPosition - Pos);201    std::memcpy(Buffer + Pos, S, N);202    CurrentPosition += N;203 204    notifyInsertion(Pos, N);205  }206 207  size_t getCurrentPosition() const { return CurrentPosition; }208  void setCurrentPosition(size_t NewPos) {209    notifyDeletion(CurrentPosition, NewPos);210    CurrentPosition = NewPos;211  }212 213  char back() const {214    DEMANGLE_ASSERT(CurrentPosition, "");215    return Buffer[CurrentPosition - 1];216  }217 218  bool empty() const { return CurrentPosition == 0; }219 220  char *getBuffer() { return Buffer; }221  char *getBufferEnd() { return Buffer + CurrentPosition - 1; }222  size_t getBufferCapacity() const { return BufferCapacity; }223};224 225template <class T> class ScopedOverride {226  T &Loc;227  T Original;228 229public:230  ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {}231 232  ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) {233    Loc_ = std::move(NewVal);234  }235  ~ScopedOverride() { Loc = std::move(Original); }236 237  ScopedOverride(const ScopedOverride &) = delete;238  ScopedOverride &operator=(const ScopedOverride &) = delete;239};240 241DEMANGLE_NAMESPACE_END242 243#endif244