2023-01-27 00:49:44 -05:00
|
|
|
/*
|
|
|
|
* Created by Brett on 26/01/23.
|
|
|
|
* Licensed under GNU General Public License V3.0
|
|
|
|
* See LICENSE file for license detail
|
|
|
|
*/
|
|
|
|
#include <blt/std/format.h>
|
|
|
|
#include <cmath>
|
2023-07-21 03:32:42 -04:00
|
|
|
#include "blt/std/logging.h"
|
2023-11-29 21:36:22 -05:00
|
|
|
#include <stack>
|
|
|
|
#include <queue>
|
2023-01-27 00:49:44 -05:00
|
|
|
|
2023-11-29 21:36:22 -05:00
|
|
|
std::string createPadding(int padAmount)
|
|
|
|
{
|
2023-01-27 00:49:44 -05:00
|
|
|
std::string padStr;
|
|
|
|
for (int i = 0; i < padAmount; i++)
|
|
|
|
padStr += " ";
|
|
|
|
return padStr;
|
|
|
|
}
|
|
|
|
|
2023-11-29 21:36:22 -05:00
|
|
|
std::vector<std::string> blt::string::TableFormatter::createTable(bool top, bool bottom)
|
|
|
|
{
|
2023-01-27 00:49:44 -05:00
|
|
|
std::vector<std::string> table;
|
|
|
|
const auto& tableHeader = generateColumnHeader();
|
|
|
|
const auto& topSeparator = generateTopSeparator(tableHeader.size());
|
2023-03-03 10:41:38 -05:00
|
|
|
const auto& lineSeparator = generateSeparator(tableHeader.size() - 1);
|
2023-01-27 00:49:44 -05:00
|
|
|
|
|
|
|
if (top)
|
|
|
|
table.push_back(topSeparator);
|
|
|
|
|
|
|
|
table.push_back(tableHeader);
|
|
|
|
table.push_back(lineSeparator);
|
|
|
|
|
2023-11-29 21:36:22 -05:00
|
|
|
for (const auto& row : rows)
|
|
|
|
{
|
2023-01-27 00:49:44 -05:00
|
|
|
std::string rowString = "|";
|
2023-11-29 21:36:22 -05:00
|
|
|
for (unsigned int i = 0; i < row.rowValues.size(); i++)
|
|
|
|
{
|
2023-01-27 00:49:44 -05:00
|
|
|
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.
|
2023-11-29 21:36:22 -05:00
|
|
|
rowString += createPadding((int) std::floor(spaceLeft / 2.0) + m_columnPadding);
|
2023-01-27 00:49:44 -05:00
|
|
|
rowString += rowValue;
|
2023-11-29 21:36:22 -05:00
|
|
|
rowString += createPadding((int) std::ceil(spaceLeft / 2.0) + m_columnPadding);
|
2023-01-27 00:49:44 -05:00
|
|
|
rowString += "|";
|
|
|
|
}
|
|
|
|
table.push_back(rowString);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bottom)
|
|
|
|
table.push_back(lineSeparator);
|
|
|
|
|
|
|
|
return table;
|
|
|
|
}
|
|
|
|
|
2023-11-29 21:36:22 -05:00
|
|
|
std::string blt::string::TableFormatter::generateColumnHeader()
|
|
|
|
{
|
2023-01-27 00:49:44 -05:00
|
|
|
updateMaxColumnLengths();
|
|
|
|
std::string header = "|";
|
|
|
|
|
2023-11-29 21:36:22 -05:00
|
|
|
for (unsigned int i = 0; i < columns.size(); i++)
|
|
|
|
{
|
2023-01-27 00:49:44 -05:00
|
|
|
const auto& column = columns[i];
|
2023-11-29 21:36:22 -05:00
|
|
|
auto columnPaddingLength = (int(column.maxColumnLength) - int(column.columnName.size())) / 2.0;
|
|
|
|
header += createPadding(int(m_columnPadding + (int) std::floor(columnPaddingLength)));
|
2023-01-27 00:49:44 -05:00
|
|
|
|
|
|
|
header += column.columnName;
|
|
|
|
|
2023-11-29 21:36:22 -05:00
|
|
|
header += createPadding(int(m_columnPadding + (int) std::ceil(columnPaddingLength)));
|
|
|
|
if (i < columns.size() - 1)
|
2023-01-27 00:49:44 -05:00
|
|
|
header += "|";
|
|
|
|
}
|
|
|
|
|
|
|
|
header += "|";
|
|
|
|
return header;
|
|
|
|
}
|
|
|
|
|
2023-11-29 21:36:22 -05:00
|
|
|
std::string blt::string::TableFormatter::generateTopSeparator(size_t size)
|
|
|
|
{
|
2023-01-29 17:10:36 -05:00
|
|
|
auto sizeOfName = m_tableName.empty() ? 0 : m_tableName.size() + 4;
|
|
|
|
auto sizeNameRemoved = size - sizeOfName;
|
|
|
|
|
|
|
|
std::string halfWidthLeftSeparator;
|
|
|
|
std::string halfWidthRightSeparator;
|
|
|
|
|
2023-11-29 21:36:22 -05:00
|
|
|
auto sizeNameFloor = (size_t) std::floor((double) sizeNameRemoved / 2.0);
|
|
|
|
auto sizeNameCeil = (size_t) std::ceil((double) sizeNameRemoved / 2.0);
|
2023-01-29 17:10:36 -05:00
|
|
|
|
|
|
|
halfWidthLeftSeparator.reserve(sizeNameCeil);
|
|
|
|
halfWidthRightSeparator.reserve(sizeNameFloor);
|
|
|
|
|
2023-02-14 22:35:40 -05:00
|
|
|
halfWidthLeftSeparator += "+";
|
|
|
|
|
2023-04-05 17:21:19 -04:00
|
|
|
for (unsigned int i = 0; i < sizeNameFloor - 1; i++)
|
2023-01-29 17:10:36 -05:00
|
|
|
halfWidthLeftSeparator += "-";
|
|
|
|
|
2023-04-05 17:21:19 -04:00
|
|
|
for (unsigned int i = 0; i < sizeNameCeil - 1; i++)
|
2023-01-29 17:10:36 -05:00
|
|
|
halfWidthRightSeparator += "-";
|
|
|
|
|
2023-02-14 22:35:40 -05:00
|
|
|
halfWidthRightSeparator += "+";
|
|
|
|
|
2023-01-29 17:10:36 -05:00
|
|
|
std::string separator;
|
|
|
|
separator += halfWidthLeftSeparator;
|
2023-11-29 21:36:22 -05:00
|
|
|
if (sizeOfName != 0)
|
|
|
|
{
|
2023-01-29 17:10:36 -05:00
|
|
|
separator += "{ ";
|
|
|
|
separator += m_tableName;
|
|
|
|
separator += " }";
|
|
|
|
}
|
|
|
|
separator += halfWidthRightSeparator;
|
|
|
|
return separator;
|
2023-01-27 00:49:44 -05:00
|
|
|
}
|
|
|
|
|
2023-11-29 21:36:22 -05:00
|
|
|
std::string blt::string::TableFormatter::generateSeparator(size_t size)
|
|
|
|
{
|
2023-01-27 00:49:44 -05:00
|
|
|
size_t nextIndex = 0;
|
|
|
|
size_t currentColumnIndex = 0;
|
|
|
|
std::string wholeWidthSeparator;
|
2023-11-29 21:36:22 -05:00
|
|
|
for (unsigned int i = 0; i < size; i++)
|
|
|
|
{
|
|
|
|
if (i == nextIndex)
|
|
|
|
{
|
|
|
|
auto currentColumnSize = columns[currentColumnIndex++].maxColumnLength + m_columnPadding * 2;
|
2023-03-03 10:41:38 -05:00
|
|
|
nextIndex += currentColumnSize + 1;
|
2023-01-27 00:49:44 -05:00
|
|
|
wholeWidthSeparator += "+";
|
|
|
|
} else
|
|
|
|
wholeWidthSeparator += "-";
|
|
|
|
}
|
2023-03-03 10:42:38 -05:00
|
|
|
wholeWidthSeparator += "+";
|
2023-01-27 00:49:44 -05:00
|
|
|
return wholeWidthSeparator;
|
|
|
|
}
|
|
|
|
|
2023-11-29 21:36:22 -05:00
|
|
|
void blt::string::TableFormatter::updateMaxColumnLengths()
|
|
|
|
{
|
|
|
|
for (unsigned int i = 0; i < columns.size(); i++)
|
|
|
|
{
|
2023-01-27 00:49:44 -05:00
|
|
|
auto& column = columns[i];
|
|
|
|
column.maxColumnLength = column.columnName.size();
|
2023-11-29 21:36:22 -05:00
|
|
|
for (const auto& row : rows)
|
|
|
|
{
|
2023-01-27 00:49:44 -05:00
|
|
|
column.maxColumnLength = std::max(column.maxColumnLength, row.rowValues[i].size());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-01-29 23:36:42 -05:00
|
|
|
|
2023-11-29 21:36:22 -05:00
|
|
|
/*
|
|
|
|
* -----------------------
|
|
|
|
* 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;
|
|
|
|
}
|