mmdeploy/service/snpe/server/text_table.h

210 lines
6.2 KiB
C++

/**
* \file sdk/load-and-run/src/text_table.h
* MegEngine is Licensed under the Apache License, Version 2.0 (the "License")
*
* Copyright (c) 2014-2021 Megvii Inc. All rights reserved.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied.
*/
#pragma once
#include <array>
#include <iomanip>
#include <ostream>
#include <sstream>
#include <string>
#include <tuple>
#include <type_traits>
#include <vector>
namespace helper {
class TextTable {
public:
enum Level { Summary, Detail };
enum class Align : int { Left, Right, Mid };
TextTable() = default;
explicit TextTable(const std::string& table_name) : m_name(table_name) {}
TextTable& horizontal(char c) {
m_row.params.horizontal = c;
return *this;
}
TextTable& vertical(char c) {
m_row.params.vertical = c;
return *this;
}
TextTable& corner(char c) {
m_row.params.corner = c;
return *this;
}
TextTable& align(Align v) {
m_row.params.align = v;
return *this;
}
TextTable& padding(size_t w) {
m_padding = w;
return *this;
}
TextTable& prefix(const std::string& str) {
m_prefix = str;
return *this;
}
template <typename T>
TextTable& add(const T& value) {
m_row.values.emplace_back(value);
if (m_cols_max_w.size() < m_row.values.size()) {
m_cols_max_w.emplace_back(m_row.values.back().length());
} else {
size_t i = m_row.values.size() - 1;
m_cols_max_w[i] = std::max(m_cols_max_w[i], m_row.values.back().length());
}
return *this;
}
template <typename T, typename std::enable_if<std::is_floating_point<T>::value, bool>::type = 0>
TextTable& add(const T& value) {
std::stringstream ss;
ss << std::setiosflags(std::ios::fixed) << std::setprecision(2);
ss << value;
m_row.values.emplace_back(ss.str());
if (m_cols_max_w.size() < m_row.values.size()) {
m_cols_max_w.emplace_back(m_row.values.back().length());
} else {
size_t i = m_row.values.size() - 1;
m_cols_max_w[i] = std::max(m_cols_max_w[i], m_row.values.back().length());
}
return *this;
}
template <typename T, typename std::enable_if<std::is_integral<T>::value, bool>::type = 0>
TextTable& add(const T& value) {
m_row.values.emplace_back(std::to_string(value));
return *this;
}
void eor() {
m_rows.emplace_back(m_row);
adjuster_last_row();
m_row.values.clear();
}
void reset() {
m_row = {};
m_cols_max_w.clear();
m_padding = 0;
m_rows.clear();
}
void show(std::ostream& os) {
if (m_rows.empty()) return;
auto& last_row = m_rows.front();
bool first = true;
for (auto& row : m_rows) {
auto& lrow = (last_row.values.size() * char_length(last_row.params.horizontal)) >
(row.values.size() * char_length(row.params.horizontal))
? last_row
: row;
// line before row
if (lrow.params.horizontal) {
if (not first) os << std::endl;
os << m_prefix;
if (lrow.params.corner) os << lrow.params.corner;
size_t skip_size = 0;
// table name
if (first) {
os << m_name;
skip_size = m_name.length();
}
for (size_t i = 0; i < lrow.values.size(); ++i) {
auto max_w = m_cols_max_w.at(i) + m_padding * 2;
if (max_w + char_length(lrow.params.corner) <= skip_size) {
skip_size = skip_size - max_w - char_length(lrow.params.corner);
continue;
}
size_t rest = max_w + char_length(lrow.params.corner) - skip_size;
skip_size = 0;
if (rest > char_length(lrow.params.corner)) {
os << std::string(rest - char_length(lrow.params.corner), lrow.params.horizontal);
rest = char_length(lrow.params.corner);
}
if (rest > 0 && lrow.params.corner) os << lrow.params.corner;
}
} else if (first) {
os << m_prefix << ' ' << m_name;
}
first = false;
os << std::endl << m_prefix;
if (row.params.vertical) os << row.params.vertical;
// row
for (size_t i = 0; i < row.values.size(); ++i) {
auto& str = row.values.at(i);
auto max_w = m_cols_max_w.at(i) + 2 * m_padding;
if (row.params.align == Align::Mid) {
mid(os, str, max_w);
} else if (row.params.align == Align::Left) {
os << std::setw(max_w) << std::left << str;
} else {
os << std::setw(max_w) << std::right << str;
}
if (row.params.vertical) os << row.params.vertical;
}
last_row = row;
}
if (last_row.params.horizontal) {
os << std::endl << m_prefix;
if (last_row.params.corner) os << last_row.params.corner;
for (size_t i = 0; i < last_row.values.size(); ++i) {
auto max_w = m_cols_max_w.at(i);
std::string tmp(max_w + m_padding * 2, last_row.params.horizontal);
os << tmp;
if (last_row.params.corner) os << last_row.params.corner;
}
}
}
private:
void adjuster_last_row() {
if (m_rows.empty()) return;
auto& row = m_rows.back();
if (row.params.horizontal == 0 or row.params.vertical == 0) {
row.params.corner = 0;
}
if (row.params.horizontal != 0 && row.params.vertical != 0 && row.params.corner == 0) {
row.params.corner = row.params.horizontal;
}
}
inline void mid(std::ostream& os, const std::string& str, size_t max_w) {
size_t l = (max_w - str.length()) / 2 + str.length();
size_t r = max_w - l;
os << std::setw(l) << std::right << str;
if (r > 0) os << std::setw(r) << ' ';
}
inline size_t char_length(char c) { return c ? 1 : 0; }
std::string m_name;
std::vector<size_t> m_cols_max_w;
size_t m_padding = 0;
std::string m_prefix = "";
struct Row {
std::vector<std::string> values;
struct Params {
Align align = Align::Left;
char horizontal = '-', vertical = '|', corner = '+';
} params;
};
std::vector<Row> m_rows;
Row m_row;
};
inline std::ostream& operator<<(std::ostream& stream, TextTable& table) {
table.show(stream);
return stream;
}
} // namespace helper