mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-04-26 13:01:34 +03:00
244 lines
6.9 KiB
C++
Vendored
244 lines
6.9 KiB
C++
Vendored
//===--- Utility.h ----------------------------------------------*- C++ -*-===//
|
|
//
|
|
// 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 "DemangleConfig.h"
|
|
|
|
#include <array>
|
|
#include <cstdint>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <limits>
|
|
#include <string_view>
|
|
|
|
DEMANGLE_NAMESPACE_BEGIN
|
|
|
|
class Node;
|
|
|
|
// 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::abort();
|
|
}
|
|
}
|
|
|
|
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+=(
|
|
std::string_view(TempPtr, Temp.data() + Temp.size() - TempPtr));
|
|
}
|
|
|
|
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;
|
|
|
|
virtual ~OutputBuffer() = default;
|
|
|
|
operator std::string_view() const {
|
|
return std::string_view(Buffer, CurrentPosition);
|
|
}
|
|
|
|
/// Called by the demangler when printing the demangle tree. By
|
|
/// default calls into \c Node::print{Left|Right} but can be overriden
|
|
/// by clients to track additional state when printing the demangled name.
|
|
virtual void printLeft(const Node &N);
|
|
virtual void printRight(const Node &N);
|
|
|
|
/// Called when we write to this object anywhere other than the end.
|
|
virtual void notifyInsertion(size_t /*Position*/, size_t /*Count*/) {}
|
|
|
|
/// Called when we make the \c CurrentPosition of this object smaller.
|
|
virtual void notifyDeletion(size_t /*OldPos*/, size_t /*NewPos*/) {}
|
|
|
|
/// 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();
|
|
|
|
struct {
|
|
/// The depth of '(' and ')' inside the currently printed template
|
|
/// arguments.
|
|
unsigned ParenDepth = 0;
|
|
|
|
/// True if we're currently printing a template argument.
|
|
bool InsideTemplate = false;
|
|
} TemplateTracker;
|
|
|
|
/// Returns true if we're currently between a '(' and ')' when printing
|
|
/// template args.
|
|
bool isInParensInTemplateArgs() const {
|
|
return TemplateTracker.ParenDepth > 0;
|
|
}
|
|
|
|
/// Returns true if we're printing template args.
|
|
bool isInsideTemplateArgs() const { return TemplateTracker.InsideTemplate; }
|
|
|
|
void printOpen(char Open = '(') {
|
|
if (isInsideTemplateArgs())
|
|
TemplateTracker.ParenDepth++;
|
|
*this += Open;
|
|
}
|
|
void printClose(char Close = ')') {
|
|
if (isInsideTemplateArgs())
|
|
TemplateTracker.ParenDepth--;
|
|
*this += Close;
|
|
}
|
|
|
|
OutputBuffer &operator+=(std::string_view 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(std::string_view R) {
|
|
size_t Size = R.size();
|
|
if (!Size)
|
|
return *this;
|
|
|
|
grow(Size);
|
|
std::memmove(Buffer + Size, Buffer, CurrentPosition);
|
|
std::memcpy(Buffer, &*R.begin(), Size);
|
|
CurrentPosition += Size;
|
|
|
|
notifyInsertion(/*Position=*/0, /*Count=*/Size);
|
|
|
|
return *this;
|
|
}
|
|
|
|
OutputBuffer &operator<<(std::string_view 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) {
|
|
DEMANGLE_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;
|
|
|
|
notifyInsertion(Pos, N);
|
|
}
|
|
|
|
size_t getCurrentPosition() const { return CurrentPosition; }
|
|
void setCurrentPosition(size_t NewPos) {
|
|
notifyDeletion(CurrentPosition, NewPos);
|
|
CurrentPosition = NewPos;
|
|
}
|
|
|
|
char back() const {
|
|
DEMANGLE_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
|