//===--- Utility.h -------------------*- mode:c++;eval:(read-only-mode) -*-===//
 
//       Do not edit! See README.txt.
 
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 
// See https://llvm.org/LICENSE.txt for license information.
 
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
//
 
//===----------------------------------------------------------------------===//
 
//
 
// Provide some utility classes for use in the demangler.
 
// There are two copies of this file in the source tree.  The one in libcxxabi
 
// is the original and the one in llvm is the copy.  Use cp-to-llvm.sh to update
 
// the copy.  See README.txt for more details.
 
//
 
//===----------------------------------------------------------------------===//
 
 
 
#ifndef DEMANGLE_UTILITY_H
 
#define DEMANGLE_UTILITY_H
 
 
 
#include "StringView.h"
 
#include <array>
 
#include <cstdint>
 
#include <cstdlib>
 
#include <cstring>
 
#include <exception>
 
#include <limits>
 
 
 
DEMANGLE_NAMESPACE_BEGIN
 
 
 
// Stream that AST nodes write their string representation into after the AST
 
// has been parsed.
 
class OutputBuffer {
 
  char *Buffer = nullptr;
 
  size_t CurrentPosition = 0;
 
  size_t BufferCapacity = 0;
 
 
 
  // Ensure there are at least N more positions in the buffer.
 
  void grow(size_t N) {
 
    size_t Need = N + CurrentPosition;
 
    if (Need > BufferCapacity) {
 
      // Reduce the number of reallocations, with a bit of hysteresis. The
 
      // number here is chosen so the first allocation will more-than-likely not
 
      // allocate more than 1K.
 
      Need += 1024 - 32;
 
      BufferCapacity *= 2;
 
      if (BufferCapacity < Need)
 
        BufferCapacity = Need;
 
      Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));
 
      if (Buffer == nullptr)
 
        std::terminate();
 
    }
 
  }
 
 
 
  OutputBuffer &writeUnsigned(uint64_t N, bool isNeg = false) {
 
    std::array<char, 21> Temp;
 
    char *TempPtr = Temp.data() + Temp.size();
 
 
 
    // Output at least one character.
 
    do {
 
      *--TempPtr = char('0' + N % 10);
 
      N /= 10;
 
    } while (N);
 
 
 
    // Add negative sign.
 
    if (isNeg)
 
      *--TempPtr = '-';
 
 
 
    return operator+=(StringView(TempPtr, Temp.data() + Temp.size()));
 
  }
 
 
 
public:
 
  OutputBuffer(char *StartBuf, size_t Size)
 
      : Buffer(StartBuf), BufferCapacity(Size) {}
 
  OutputBuffer(char *StartBuf, size_t *SizePtr)
 
      : OutputBuffer(StartBuf, StartBuf ? *SizePtr : 0) {}
 
  OutputBuffer() = default;
 
  // Non-copyable
 
  OutputBuffer(const OutputBuffer &) = delete;
 
  OutputBuffer &operator=(const OutputBuffer &) = delete;
 
 
 
  operator StringView() const { return StringView(Buffer, CurrentPosition); }
 
 
 
  /// If a ParameterPackExpansion (or similar type) is encountered, the offset
 
  /// into the pack that we're currently printing.
 
  unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
 
  unsigned CurrentPackMax = std::numeric_limits<unsigned>::max();
 
 
 
  /// When zero, we're printing template args and '>' needs to be parenthesized.
 
  /// Use a counter so we can simply increment inside parentheses.
 
  unsigned GtIsGt = 1;
 
 
 
  bool isGtInsideTemplateArgs() const { return GtIsGt == 0; }
 
 
 
  void printOpen(char Open = '(') {
 
    GtIsGt++;
 
    *this += Open;
 
  }
 
  void printClose(char Close = ')') {
 
    GtIsGt--;
 
    *this += Close;
 
  }
 
 
 
  OutputBuffer &operator+=(StringView R) {
 
    if (size_t Size = R.size()) {
 
      grow(Size);
 
      std::memcpy(Buffer + CurrentPosition, R.begin(), Size);
 
      CurrentPosition += Size;
 
    }
 
    return *this;
 
  }
 
 
 
  OutputBuffer &operator+=(char C) {
 
    grow(1);
 
    Buffer[CurrentPosition++] = C;
 
    return *this;
 
  }
 
 
 
  OutputBuffer &prepend(StringView R) {
 
    size_t Size = R.size();
 
 
 
    grow(Size);
 
    std::memmove(Buffer + Size, Buffer, CurrentPosition);
 
    std::memcpy(Buffer, R.begin(), Size);
 
    CurrentPosition += Size;
 
 
 
    return *this;
 
  }
 
 
 
  OutputBuffer &operator<<(StringView R) { return (*this += R); }
 
 
 
  OutputBuffer &operator<<(char C) { return (*this += C); }
 
 
 
  OutputBuffer &operator<<(long long N) {
 
    return writeUnsigned(static_cast<unsigned long long>(std::abs(N)), N < 0);
 
  }
 
 
 
  OutputBuffer &operator<<(unsigned long long N) {
 
    return writeUnsigned(N, false);
 
  }
 
 
 
  OutputBuffer &operator<<(long N) {
 
    return this->operator<<(static_cast<long long>(N));
 
  }
 
 
 
  OutputBuffer &operator<<(unsigned long N) {
 
    return this->operator<<(static_cast<unsigned long long>(N));
 
  }
 
 
 
  OutputBuffer &operator<<(int N) {
 
    return this->operator<<(static_cast<long long>(N));
 
  }
 
 
 
  OutputBuffer &operator<<(unsigned int N) {
 
    return this->operator<<(static_cast<unsigned long long>(N));
 
  }
 
 
 
  void insert(size_t Pos, const char *S, size_t N) {
 
    assert(Pos <= CurrentPosition);
 
    if (N == 0)
 
      return;
 
    grow(N);
 
    std::memmove(Buffer + Pos + N, Buffer + Pos, CurrentPosition - Pos);
 
    std::memcpy(Buffer + Pos, S, N);
 
    CurrentPosition += N;
 
  }
 
 
 
  size_t getCurrentPosition() const { return CurrentPosition; }
 
  void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
 
 
 
  char back() const {
 
    assert(CurrentPosition);
 
    return Buffer[CurrentPosition - 1];
 
  }
 
 
 
  bool empty() const { return CurrentPosition == 0; }
 
 
 
  char *getBuffer() { return Buffer; }
 
  char *getBufferEnd() { return Buffer + CurrentPosition - 1; }
 
  size_t getBufferCapacity() const { return BufferCapacity; }
 
};
 
 
 
template <class T> class ScopedOverride {
 
  T &Loc;
 
  T Original;
 
 
 
public:
 
  ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {}
 
 
 
  ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) {
 
    Loc_ = std::move(NewVal);
 
  }
 
  ~ScopedOverride() { Loc = std::move(Original); }
 
 
 
  ScopedOverride(const ScopedOverride &) = delete;
 
  ScopedOverride &operator=(const ScopedOverride &) = delete;
 
};
 
 
 
DEMANGLE_NAMESPACE_END
 
 
 
#endif