blob: 3fe43ad6cf7cd24c89b49962590f1f63d323262c [file] [log] [blame]
//===--- PrefixMap.cpp - Out-of-line helpers for the PrefixMap structure --===//
//
// 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
//
//===----------------------------------------------------------------------===//
#include "swift/Basic/PrefixMap.h"
#include "swift/Basic/QuotedString.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Compiler.h"
using namespace swift;
#if __has_attribute(may_alias) || LLVM_GNUC_PREREQ(3, 0, 0)
#define LLVM_MAY_ALIAS __attribute__((may_alias))
#else
#define LLVM_MAY_ALIAS
#endif
namespace {
enum class ChildKind { Left, Right, Further, Root };
// We'd like the dump routine to be present in all builds, but it's
// a pretty large amount of code, most of which is not sensitive to the
// actual key and value data. If we try to have a common implementation,
// we're left with the problem of describing the layout of a node when
// that's technically instantiation-specific. Redefining the struct here
// is technically an aliasing violation, but we can just tell the compilers
// that actually use TBAA that this is okay.
typedef struct _Node Node LLVM_MAY_ALIAS;
struct _Node {
// If you change the layout in the header, you'll need to change it here.
// (This comment is repeated there.)
Node *Left, *Right, *Further;
};
class TreePrinter {
llvm::raw_ostream &Out;
void (&PrintNodeData)(llvm::raw_ostream &out, void *node);
SmallString<40> Indent;
public:
TreePrinter(llvm::raw_ostream &out,
void (&printNodeData)(llvm::raw_ostream &out, void *node))
: Out(out), PrintNodeData(printNodeData) {}
struct IndentScope {
TreePrinter *Printer;
size_t OldLength;
IndentScope(TreePrinter *printer, StringRef indent)
: Printer(printer), OldLength(printer->Indent.size()) {
Printer->Indent += indent;
}
~IndentScope() { Printer->Indent.resize(OldLength); }
};
void print(Node *node, ChildKind childKind) {
// The top-level indents here create the line to the node we're
// trying to print.
if (node->Left) {
IndentScope ms(this, (childKind == ChildKind::Left ||
childKind == ChildKind::Root) ? " " : "| ");
print(node->Left, ChildKind::Left);
}
{
Out << Indent;
if (childKind == ChildKind::Root) {
Out << "+- ";
} else if (childKind == ChildKind::Left) {
Out << "/- ";
} else if (childKind == ChildKind::Right) {
Out << "\\- ";
} else if (childKind == ChildKind::Further) {
Out << "\\-> ";
}
PrintNodeData(Out, node);
Out << '\n';
}
if (node->Further || node->Right) {
IndentScope ms(this, (childKind == ChildKind::Right ||
childKind == ChildKind::Further ||
childKind == ChildKind::Root) ? " " : "| ");
if (node->Further) {
// Further indent, and include the line to the right child if
// there is one.
IndentScope is(this, node->Right ? "| " : " ");
print(node->Further, ChildKind::Further);
}
if (node->Right) {
print(node->Right, ChildKind::Right);
}
}
}
};
} // end anonymous namespace
void swift::printOpaquePrefixMap(raw_ostream &out, void *_root,
void (*printNodeData)(raw_ostream &out, void *node)) {
auto root = reinterpret_cast<Node*>(_root);
if (!root) {
out << "(empty)\n";
return;
}
TreePrinter(out, *printNodeData).print(root, ChildKind::Root);
}
void PrefixMapKeyPrinter<char>::print(raw_ostream &out, ArrayRef<char> key) {
out << QuotedString(StringRef(key.data(), key.size()));
};
void PrefixMapKeyPrinter<unsigned char>::print(raw_ostream &out,
ArrayRef<unsigned char> key) {
out << '\'';
for (auto byte : key) {
if (byte < 16) out << '0';
out.write_hex(byte);
}
out << '\'';
}