Skip to content

Instantly share code, notes, and snippets.

@snooze6214

snooze6214/Tree.h

Created Jun 19, 2021
Embed
What would you like to do?
we do a little pretty printed trees here
#pragma once
#include <vector>
#include <string>
#include <sstream>
#include <algorithm>
#include <ostream>
class TextBox {
public:
struct xy {
TextBox& tb;
int x, y;
xy operator<< (const std::string& s) const {
return {tb, x + tb.puts(x, y, s), y};
}
xy operator<< (const int i) const {
std::string s = std::to_string(i);
return {tb, x + tb.puts(x, y, s), y};
}
xy operator<< (const char c) const {
tb.putc(x, y, c);
return {tb, x + 1, y};
}
xy operator<< (const TextBox& _tb) const {
tb.puttb(x, y, _tb);
return {tb, x + _tb.width(), y};
}
};
std::string str() const {
std::stringstream ss;
for (auto& s : m_buffer) {
//ss << s << '\n';
for (char c : s) {
if (c > 0b1111)
ss << c;
else {
switch (static_cast<int>(c) & 0b1111) {
case 0b01:
ss << '-';
break;
case 0b10:
ss << '|';
break;
case 0b11:
ss << '+';
break;
default:
ss << c;
}
}
}
ss << '\n';
}
return ss.str();
}
TextBox::xy operator() (int x, int y) const {
return {const_cast<TextBox&>(*this), x, y};
}
int width() const {
int w = -1;
for (auto& s : m_buffer)
w = std::max(w, static_cast<int>(s.size()));
return w;
}
int height() const {
return m_buffer.size();
}
void hline(int x, int y, int width) {
if (y >= m_buffer.size())
m_buffer.resize(y+1);
if (x+width >= m_buffer[y].size())
m_buffer[y].resize(x+width, ' ');
for (int i = 0; i < width; i++) {
if (m_buffer[y][x+i] > 0b1111)
m_buffer[y][x+i] = 0;
m_buffer[y][x+i] |= 0b1;
}
}
void vline(int x, int y, int height) {
if (y+height >= m_buffer.size())
m_buffer.resize(y+height);
for (int i = 0; i < height; i++) {
if (x >= m_buffer[y+i].size())
m_buffer[y+i].resize(x+1, ' ');
if (m_buffer[y+i][x] > 0b1111)
m_buffer[y+i][x] = 0;
m_buffer[y+i][x] |= 0b10;
}
}
private:
void putc(int x, int y, char c) {
if (y >= m_buffer.size())
m_buffer.resize(y+1);
if (x >= m_buffer[y].size())
m_buffer[y].resize(x+1, ' ');
m_buffer[y][x] = c;
}
int puts(int x, int y, const std::string& s) {
if (s.empty()) return x;
for (int i = 0; i < s.size(); i++)
putc(x+i, y, s[i]);
return x + s.size();
}
void puttb(int x, int y, const TextBox& tb) {
for (int i = 0; i < tb.height(); i++) {
puts(x, y+i, tb.m_buffer[i]);
}
}
private:
std::vector<std::string> m_buffer;
};
template<typename T>
struct Tree {
struct TreeNode {
T data;
std::vector<TreeNode> children;
TreeNode(T _data) : data(_data) {}
void add_child(T c) {
children.emplace_back(c);
}
};
TreeNode root;
Tree(T _root) : root(_root) {}
friend std::ostream& operator<< (std::ostream& os, Tree<T>& tree) {
TextBox tb = create_tree_textbox(tree.root);
os << tb.str();
return os;
}
private:
static TextBox create_tree_textbox(const TreeNode& node) {
TextBox tb;
constexpr int padding = 2;
tb(0, 0) << node.data;
if (node.children.empty())
return tb;
std::vector<TextBox> child_tbs;
for (auto child : node.children)
child_tbs.push_back(create_tree_textbox(child));
tb.vline(0, 1, 1);
int i = 0;
for (auto child : child_tbs) {
tb.vline(i, 2, 2);
tb(i, 4) << child;
i += child.width() + padding;
}
tb.hline(0, 2, i - child_tbs[child_tbs.size() - 1].width() - padding + 1);
return tb;
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment