blob: a98467fead0234e68e7d16d16284edd5aed311fc [file] [log] [blame]
//===--- Demangler.h - String to Node-Tree Demangling -----------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file contains shared code between the old and new remanglers.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_DEMANGLING_BASEREMANGLER_H
#define SWIFT_DEMANGLING_BASEREMANGLER_H
#include "swift/Demangling/Demangler.h"
#include "swift/Demangling/NamespaceMacros.h"
#include <unordered_map>
using namespace swift::Demangle;
using llvm::StringRef;
namespace swift {
namespace Demangle {
SWIFT_BEGIN_INLINE_NAMESPACE
// An entry in the remangler's substitution map.
class SubstitutionEntry {
Node *TheNode = nullptr;
size_t StoredHash = 0;
bool treatAsIdentifier = false;
public:
void setNode(Node *node, bool treatAsIdentifier) {
this->treatAsIdentifier = treatAsIdentifier;
TheNode = node;
deepHash(node);
}
struct Hasher {
size_t operator()(const SubstitutionEntry &entry) const {
return entry.StoredHash;
}
};
private:
friend bool operator==(const SubstitutionEntry &lhs,
const SubstitutionEntry &rhs) {
if (lhs.StoredHash != rhs.StoredHash)
return false;
if (lhs.treatAsIdentifier != rhs.treatAsIdentifier)
return false;
if (lhs.treatAsIdentifier) {
return identifierEquals(lhs.TheNode, rhs.TheNode);
}
return lhs.deepEquals(lhs.TheNode, rhs.TheNode);
}
static bool identifierEquals(Node *lhs, Node *rhs);
void combineHash(size_t newValue) {
StoredHash = 33 * StoredHash + newValue;
}
void deepHash(Node *node);
bool deepEquals(Node *lhs, Node *rhs) const;
};
/// The output string for the Remangler.
///
/// It's allocating the string with the provided Factory.
class RemanglerBuffer {
CharVector Stream;
NodeFactory &Factory;
public:
RemanglerBuffer(NodeFactory &Factory) : Factory(Factory) {
Stream.init(Factory, 32);
}
void reset(size_t toPos) { Stream.resetSize(toPos); }
StringRef strRef() const { return Stream.str(); }
RemanglerBuffer &operator<<(char c) & {
Stream.push_back(c, Factory);
return *this;
}
RemanglerBuffer &operator<<(llvm::StringRef Value) & {
Stream.append(Value, Factory);
return *this;
}
RemanglerBuffer &operator<<(int n) & {
Stream.append(n, Factory);
return *this;
}
RemanglerBuffer &operator<<(unsigned n) & {
Stream.append((unsigned long long)n, Factory);
return *this;
}
RemanglerBuffer &operator<<(unsigned long n) & {
Stream.append((unsigned long long)n, Factory);
return *this;
}
RemanglerBuffer &operator<<(unsigned long long n) & {
Stream.append(n, Factory);
return *this;
}
};
/// The base class for the old and new remangler.
class RemanglerBase {
protected:
// Used to allocate temporary nodes and the output string (in Buffer).
NodeFactory &Factory;
// An efficient hash-map implementation in the spirit of llvm's SmallPtrSet:
// The first 16 substitutions are stored in an inline-allocated array to avoid
// malloc calls in the common case.
// Lookup is still reasonable fast because there are max 16 elements in the
// array.
static const size_t InlineSubstCapacity = 16;
SubstitutionEntry InlineSubstitutions[InlineSubstCapacity];
size_t NumInlineSubsts = 0;
// The "overflow" for InlineSubstitutions. Only if InlineSubstitutions is
// full, new substitutions are stored in OverflowSubstitutions.
std::unordered_map<SubstitutionEntry, unsigned, SubstitutionEntry::Hasher>
OverflowSubstitutions;
RemanglerBuffer Buffer;
protected:
RemanglerBase(NodeFactory &Factory) : Factory(Factory), Buffer(Factory) { }
/// Find a substitution and return its index.
/// Returns -1 if no substitution is found.
int findSubstitution(const SubstitutionEntry &entry);
/// Adds a substitution.
void addSubstitution(const SubstitutionEntry &entry);
/// Resets the output string buffer to \p toPos.
void resetBuffer(size_t toPos) { Buffer.reset(toPos); }
public:
/// Append a custom string to the output buffer.
void append(StringRef str) { Buffer << str; }
StringRef getBufferStr() const { return Buffer.strRef(); }
std::string str() {
return getBufferStr().str();
}
};
SWIFT_END_INLINE_NAMESPACE
} // end namespace Demangle
} // end namespace swift
#endif // SWIFT_DEMANGLING_BASEREMANGLER_H