Autism (Ascii trees)

making ascii trees because fun
v1
Brett 2023-11-29 21:36:22 -05:00
parent d589056a8d
commit da32f9b98a
3 changed files with 339 additions and 63 deletions

View File

@ -13,40 +13,66 @@
#include <blt/math/math.h>
#include <algorithm>
namespace blt::string {
namespace blt::string
{
template<typename T>
static inline std::string withGrouping(T t, size_t group = 3){
static inline std::string withGrouping(T t, size_t group = 3)
{
// TODO: all this + make it faster
static_assert(std::is_integral_v<T>, "Must be integer type! (Floats currently not supported!)");
auto str = std::to_string(t);
std::string ret;
ret.reserve(str.size());
size_t count = 0;
for (int64_t i = str.size() - 1; i >= 0; i--){
for (int64_t i = str.size() - 1; i >= 0; i--)
{
ret += str[i];
if (count++ % (group) == group-1 && i != 0)
if (count++ % (group) == group - 1 && i != 0)
ret += ',';
}
std::reverse(ret.begin(), ret.end());
return ret;
}
static inline std::string fromBytes(unsigned long bytes){
if (bytes > 1073741824) {
static inline std::string fromBytes(unsigned long bytes)
{
if (bytes > 1073741824)
{
// gigabyte
return std::to_string(round_up<3>((double) bytes / 1024.0 / 1024.0 / 1024.0)) += "gb";
} else if (bytes > 1048576) {
} else if (bytes > 1048576)
{
// megabyte
return std::to_string(round_up<3>((double)bytes / 1024.0 / 1024.0)) += "mb";
} else if (bytes > 1024) {
return std::to_string(round_up<3>((double) bytes / 1024.0 / 1024.0)) += "mb";
} else if (bytes > 1024)
{
// kilobyte
return std::to_string(round_up<3>((double)bytes / 1024.0)) += "kb";
} else {
return std::to_string(round_up<3>((double) bytes / 1024.0)) += "kb";
} else
{
return std::to_string(bytes) += "b";
}
}
// TODO: update table formatter to use these!
/**
* creates a line starting/ending with ending char filled between with spacing char
* @param totalLength total length to generate
* @param endingChar beginning and ending char to use
* @param spacingChar char to use for spacing
* @return a generated line string eg: +--------+
*/
std::string createLine(size_t totalLength, char endingChar, char spacingChar);
/**
* Create a padding string using length and spacing char
* @param length length of string to generate
* @param spacing char to use to generate padding
* @return a padding string
*/
std::string createPadding(size_t length, char spacing = ' ');
// TODO template the padding functions:
/**
@ -55,13 +81,13 @@ namespace blt::string {
* @param expectedLength expected length of the string.
* @return a space padded string
*/
static inline std::string postPadWithSpaces(const std::string& str, size_t expectedLength) {
static inline std::string postPadWithSpaces(const std::string& str, size_t expectedLength)
{
auto currentSize = (int) (str.length() - 1);
if ((int) expectedLength - currentSize <= 0)
return str;
auto paddedString = str;
for (size_t i = 0; i < expectedLength - currentSize; i++)
paddedString += " ";
paddedString += createPadding(expectedLength - currentSize);
return paddedString;
}
@ -71,26 +97,29 @@ namespace blt::string {
* @param expectedLength expected length of the string.
* @return a space padded string
*/
static inline std::string prePadWithSpaces(const std::string& str, size_t expectedLength) {
static inline std::string prePadWithSpaces(const std::string& str, size_t expectedLength)
{
auto currentSize = str.length() - 1;
auto paddedString = std::string();
for (unsigned int i = 0; i < expectedLength - currentSize; i++)
paddedString += " ";
paddedString += createPadding(expectedLength - currentSize);
paddedString += str;
return paddedString;
}
struct utf8_string {
struct utf8_string
{
char* characters;
unsigned int size;
};
// taken from java, adapted for c++.
static inline utf8_string createUTFString(const std::string& str) {
static inline utf8_string createUTFString(const std::string& str)
{
const auto strlen = (unsigned int) str.size();
unsigned int utflen = strlen;
for (unsigned int i = 0; i < strlen; i++) {
for (unsigned int i = 0; i < strlen; i++)
{
unsigned char c = str[i];
if (c >= 0x80 || c == 0)
utflen += 1;
@ -108,21 +137,26 @@ namespace blt::string {
chars.characters[count++] = (char) ((utflen >> 0) & 0xFF);
unsigned int i = 0;
for (i = 0; i < strlen; i++) { // optimized for initial run of ASCII
for (i = 0; i < strlen; i++)
{ // optimized for initial run of ASCII
int c = (unsigned char) str[i];
if (c >= 0x80 || c == 0) break;
chars.characters[count++] = (char) c;
}
for (; i < strlen; i++) {
for (; i < strlen; i++)
{
int c = (unsigned char) str[i];
if (c < 0x80 && c != 0) {
if (c < 0x80 && c != 0)
{
chars.characters[count++] = (char) c;
} else if (c >= 0x800) {
} else if (c >= 0x800)
{
chars.characters[count++] = (char) (0xE0 | ((c >> 12) & 0x0F));
chars.characters[count++] = (char) (0x80 | ((c >> 6) & 0x3F));
chars.characters[count++] = (char) (0x80 | ((c >> 0) & 0x3F));
} else {
} else
{
chars.characters[count++] = (char) (0xC0 | ((c >> 6) & 0x1F));
chars.characters[count++] = (char) (0x80 | ((c >> 0) & 0x3F));
}
@ -130,7 +164,8 @@ namespace blt::string {
return chars;
}
static inline std::string getStringFromUTF8(const utf8_string& str) {
static inline std::string getStringFromUTF8(const utf8_string& str)
{
int utflen = (int) str.size;
int c, char2, char3;
int count = 0;
@ -138,16 +173,19 @@ namespace blt::string {
auto chararr = new char[utflen + 1];
while (count < utflen) {
while (count < utflen)
{
c = (int) str.characters[count] & 0xff;
if (c > 127) break;
count++;
chararr[chararr_count++] = (char) c;
}
while (count < utflen) {
while (count < utflen)
{
c = (int) str.characters[count] & 0xff;
switch (c >> 4) {
switch (c >> 4)
{
case 0:
case 1:
case 2:
@ -192,23 +230,27 @@ namespace blt::string {
}
}
chararr[utflen] = '\0';
std::string strs {chararr};
std::string strs{chararr};
delete[] chararr;
return strs;
}
struct TableColumn {
struct TableColumn
{
std::string columnName;
size_t maxColumnLength = 0;
TableColumn(std::string columnName): columnName(std::move(columnName)) {}
TableColumn(std::string columnName): columnName(std::move(columnName))
{}
};
struct TableRow {
struct TableRow
{
std::vector<std::string> rowValues;
};
class TableFormatter {
class TableFormatter
{
private:
std::string m_tableName;
int m_columnPadding;
@ -224,19 +266,23 @@ namespace blt::string {
void updateMaxColumnLengths();
[[nodiscard]] inline size_t columnSize(const TableColumn& column) const {
[[nodiscard]] inline size_t columnSize(const TableColumn& column) const
{
return column.columnName.size() + m_columnPadding * 2;
}
public:
explicit TableFormatter(std::string tableName = "", int columnPadding = 2, int maxColumnWidth = 500):
m_tableName(std::move(tableName)), m_columnPadding(columnPadding), m_maxColumnWidth(maxColumnWidth) {}
m_tableName(std::move(tableName)), m_columnPadding(columnPadding), m_maxColumnWidth(maxColumnWidth)
{}
inline void addColumn(const TableColumn& column) {
inline void addColumn(const TableColumn& column)
{
columns.push_back(column);
}
inline void addRow(TableRow row) {
inline void addRow(TableRow row)
{
if (row.rowValues.size() > columns.size())
throw "Cannot insert more rows than columns!\n";
// ensure every row populates every column. This is important as the table generator assumes that all rows are complete!
@ -246,7 +292,8 @@ namespace blt::string {
rows.push_back(std::move(row));
}
inline void addRow(const std::initializer_list<std::string>& values) {
inline void addRow(const std::initializer_list<std::string>& values)
{
TableRow row;
for (const auto& value : values)
row.rowValues.push_back(value);
@ -256,5 +303,65 @@ namespace blt::string {
std::vector<std::string> createTable(bool top = false, bool bottom = false);
};
class TreeFormatter
{
public:
struct Node
{
std::string data;
Node* left = nullptr;
Node* right = nullptr;
explicit Node(std::string data): data(std::move(data))
{}
Node* with(Node* l, Node* r = nullptr)
{
left = l;
right = r;
return this;
}
~Node()
{
delete left;
delete right;
}
};
private:
// data classes
struct TreeFormat
{
int verticalSpacing;
int horizontalSpacing;
int verticalPadding;
int horizontalPadding;
TreeFormat(): verticalSpacing(2), horizontalSpacing(4), verticalPadding(1), horizontalPadding(4)
{}
} format;
Node* root;
public:
explicit TreeFormatter(std::string rootData, TreeFormat format = {}): format(format), root(new Node(std::move(rootData)))
{}
std::vector<std::string> generateBox(Node* node) const;
inline Node* getRoot()
{
return root;
}
std::vector<std::string> construct();
~TreeFormatter()
{
delete root;
}
};
}
#endif //BLT_TESTS_FORMAT_H

View File

@ -6,15 +6,19 @@
#include <blt/std/format.h>
#include <cmath>
#include "blt/std/logging.h"
#include <stack>
#include <queue>
std::string createPadding(int padAmount) {
std::string createPadding(int padAmount)
{
std::string padStr;
for (int i = 0; i < padAmount; i++)
padStr += " ";
return padStr;
}
std::vector<std::string> blt::string::TableFormatter::createTable(bool top, bool bottom) {
std::vector<std::string> blt::string::TableFormatter::createTable(bool top, bool bottom)
{
std::vector<std::string> table;
const auto& tableHeader = generateColumnHeader();
const auto& topSeparator = generateTopSeparator(tableHeader.size());
@ -26,16 +30,18 @@ std::vector<std::string> blt::string::TableFormatter::createTable(bool top, bool
table.push_back(tableHeader);
table.push_back(lineSeparator);
for (const auto& row : rows) {
for (const auto& row : rows)
{
std::string rowString = "|";
for (unsigned int i = 0; i < row.rowValues.size(); i++) {
for (unsigned int i = 0; i < row.rowValues.size(); i++)
{
const auto& rowValue = row.rowValues[i];
const auto& column = columns[i];
const int spaceLeft = int(column.maxColumnLength) - int(rowValue.size());
// we want to prefer putting the space on the right size, flooring left and ceiling right ensures this.
rowString += createPadding((int)std::floor(spaceLeft/2.0) + m_columnPadding);
rowString += createPadding((int) std::floor(spaceLeft / 2.0) + m_columnPadding);
rowString += rowValue;
rowString += createPadding((int)std::ceil(spaceLeft/2.0) + m_columnPadding);
rowString += createPadding((int) std::ceil(spaceLeft / 2.0) + m_columnPadding);
rowString += "|";
}
table.push_back(rowString);
@ -47,19 +53,21 @@ std::vector<std::string> blt::string::TableFormatter::createTable(bool top, bool
return table;
}
std::string blt::string::TableFormatter::generateColumnHeader() {
std::string blt::string::TableFormatter::generateColumnHeader()
{
updateMaxColumnLengths();
std::string header = "|";
for (unsigned int i = 0; i < columns.size(); i++) {
for (unsigned int i = 0; i < columns.size(); i++)
{
const auto& column = columns[i];
auto columnPaddingLength = (int(column.maxColumnLength) - int(column.columnName.size()))/2.0;
header += createPadding(int(m_columnPadding + (int)std::floor(columnPaddingLength)));
auto columnPaddingLength = (int(column.maxColumnLength) - int(column.columnName.size())) / 2.0;
header += createPadding(int(m_columnPadding + (int) std::floor(columnPaddingLength)));
header += column.columnName;
header += createPadding(int(m_columnPadding + (int)std::ceil(columnPaddingLength)));
if (i < columns.size()-1)
header += createPadding(int(m_columnPadding + (int) std::ceil(columnPaddingLength)));
if (i < columns.size() - 1)
header += "|";
}
@ -67,15 +75,16 @@ std::string blt::string::TableFormatter::generateColumnHeader() {
return header;
}
std::string blt::string::TableFormatter::generateTopSeparator(size_t size) {
std::string blt::string::TableFormatter::generateTopSeparator(size_t size)
{
auto sizeOfName = m_tableName.empty() ? 0 : m_tableName.size() + 4;
auto sizeNameRemoved = size - sizeOfName;
std::string halfWidthLeftSeparator;
std::string halfWidthRightSeparator;
auto sizeNameFloor = (size_t) std::floor((double)sizeNameRemoved/2.0);
auto sizeNameCeil = (size_t) std::ceil((double)sizeNameRemoved/2.0);
auto sizeNameFloor = (size_t) std::floor((double) sizeNameRemoved / 2.0);
auto sizeNameCeil = (size_t) std::ceil((double) sizeNameRemoved / 2.0);
halfWidthLeftSeparator.reserve(sizeNameCeil);
halfWidthRightSeparator.reserve(sizeNameFloor);
@ -92,7 +101,8 @@ std::string blt::string::TableFormatter::generateTopSeparator(size_t size) {
std::string separator;
separator += halfWidthLeftSeparator;
if (sizeOfName != 0) {
if (sizeOfName != 0)
{
separator += "{ ";
separator += m_tableName;
separator += " }";
@ -101,13 +111,16 @@ std::string blt::string::TableFormatter::generateTopSeparator(size_t size) {
return separator;
}
std::string blt::string::TableFormatter::generateSeparator(size_t size) {
std::string blt::string::TableFormatter::generateSeparator(size_t size)
{
size_t nextIndex = 0;
size_t currentColumnIndex = 0;
std::string wholeWidthSeparator;
for (unsigned int i = 0; i < size; i++) {
if (i == nextIndex) {
auto currentColumnSize = columns[currentColumnIndex++].maxColumnLength + m_columnPadding*2;
for (unsigned int i = 0; i < size; i++)
{
if (i == nextIndex)
{
auto currentColumnSize = columns[currentColumnIndex++].maxColumnLength + m_columnPadding * 2;
nextIndex += currentColumnSize + 1;
wholeWidthSeparator += "+";
} else
@ -117,13 +130,113 @@ std::string blt::string::TableFormatter::generateSeparator(size_t size) {
return wholeWidthSeparator;
}
void blt::string::TableFormatter::updateMaxColumnLengths() {
for (unsigned int i = 0; i < columns.size(); i++) {
void blt::string::TableFormatter::updateMaxColumnLengths()
{
for (unsigned int i = 0; i < columns.size(); i++)
{
auto& column = columns[i];
column.maxColumnLength = column.columnName.size();
for (const auto& row : rows) {
for (const auto& row : rows)
{
column.maxColumnLength = std::max(column.maxColumnLength, row.rowValues[i].size());
}
}
}
/*
* -----------------------
* Tree Formatter
* -----------------------
*/
struct node_data
{
blt::string::TreeFormatter::Node* node;
size_t level;
node_data(blt::string::TreeFormatter::Node* node, size_t level): node(node), level(level)
{}
};
std::vector<std::string> blt::string::TreeFormatter::construct()
{
std::vector<std::string> lines;
std::stack<node_data> nodes;
std::queue<node_data> bfs;
bfs.emplace(root, 0);
while (!bfs.empty())
{
auto n = bfs.front();
nodes.push(n);
std::cout << "Node at level " << n.level << " " << bfs.size() << "\n";
if (n.node->left != nullptr)
bfs.emplace(n.node->left, n.level + 1);
if (n.node->right != nullptr)
bfs.emplace(n.node->right, n.level + 1);
bfs.pop();
}
return lines;
}
std::vector<std::string> blt::string::TreeFormatter::generateBox(blt::string::TreeFormatter::Node* node) const
{
if (node == nullptr)
return {};
std::vector<std::string> lines;
auto& data = node->data;
auto dataLength = data.length();
auto paddingLeft = format.horizontalPadding;
auto paddingRight = format.horizontalPadding;
auto totalLength = paddingLeft + paddingRight + dataLength;
if (totalLength % 2 != 0)
{
paddingRight += 1;
totalLength += 1;
}
// create horizontal line based on the calculated length
std::string hline = createLine(totalLength, '+', '-');
std::string paddedLine = createLine(totalLength, '|', ' ');
std::string dataStr;
dataStr.reserve(totalLength);
dataStr += '|';
dataStr += createPadding(paddingLeft - 1);
dataStr += data;
dataStr += createPadding(paddingRight - 1);
dataStr += '|';
lines.push_back(hline);
for (int i = 0; i < format.verticalPadding; i++)
lines.push_back(paddedLine);
lines.push_back(std::move(dataStr));
for (int i = 0; i < format.verticalPadding; i++)
lines.push_back(paddedLine);
lines.push_back(std::move(hline));
return lines;
}
std::string blt::string::createLine(size_t totalLength, char endingChar, char spacingChar)
{
std::string line;
line.reserve(totalLength);
line += endingChar;
line += createPadding(totalLength - 2, spacingChar);
line += endingChar;
return line;
}
std::string blt::string::createPadding(size_t length, char spacing)
{
std::string padding;
padding.reserve(length);
for (size_t i = 0; i < length; i++)
padding += spacing;
return padding;
}

View File

@ -16,6 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <blt/std/utility.h>
#include <blt/std/format.h>
#include <blt/std/logging.h>
#include <utility_test.h>
#include <vector>
@ -23,12 +24,17 @@
#include <iostream>
#include <limits>
std::optional<int> get()
{
return 10;
}
void printLines(const std::vector<std::string>& lines)
{
for (const auto& v : lines)
std::cout << v << "\n";
}
void blt::test::utility::run()
{
//std::vector<int> temp;
@ -37,4 +43,54 @@ void blt::test::utility::run()
{
}
blt::string::TableFormatter parkerLove("Intrinsic Action Value Table");
parkerLove.addColumn({"Thing"});
parkerLove.addColumn({"Value"});
parkerLove.addRow({"Cuddles", "1 / minute"});
parkerLove.addRow({"Hand Job", "10"});
parkerLove.addRow({"Head", "100"});
parkerLove.addRow({"Sleeping Together (Non-Sexual)", "1,000"});
parkerLove.addRow({"Actual Sex", "5,000"});
parkerLove.addRow({"Sleeping Together (Sexual)", "10,000"});
parkerLove.addRow({"Relationship (I would do anything for you)", "1,000,000,000,000"});
printLines(parkerLove.createTable(true, true));
blt::string::TreeFormatter treeFormatter("I love Men");
treeFormatter.getRoot()->with(
new string::TreeFormatter::Node("Guys"),
new string::TreeFormatter::Node("Femboys"));
printLines(treeFormatter.construct());
}