Files
paddlepaddle--paddle/paddle/fluid/inference/utils/table_printer.cc
T
2026-07-13 12:40:42 +08:00

214 lines
6.0 KiB
C++

// Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "paddle/fluid/inference/utils/table_printer.h"
#ifdef _WIN32
// suppress the min and max definitions in Windef.h.
#define NOMINMAX
#include <Windows.h>
#else
#include <sys/ioctl.h>
#include <unistd.h>
#endif
#include <algorithm>
#include <iomanip>
#include <numeric>
#include <sstream>
#include <string>
#include <vector>
namespace paddle::inference {
std::string TablePrinter::PrintTable() {
std::stringstream ss;
ss << "\n";
CalcLayout();
AddRowDivider(ss);
AddRow(ss, 0);
AddRowDivider(ss);
for (size_t i = 1; i < data_.size(); ++i) {
if (data_[i].empty()) {
AddRowDivider(ss);
} else {
AddRow(ss, i);
}
}
AddRowDivider(ss);
return ss.str();
}
TablePrinter::TablePrinter(const std::vector<std::string>& header) {
size_t terminal_width = 500;
#ifdef _WIN32
CONSOLE_SCREEN_BUFFER_INFO csbi;
int ret = GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
if (ret && (csbi.dwSize.X != 0)) {
terminal_width = csbi.dwSize.X;
}
#else
struct winsize terminal_size = {};
int status = ioctl(STDOUT_FILENO, TIOCGWINSZ, &terminal_size);
if (status == 0 && terminal_size.ws_col != 0) {
terminal_width = terminal_size.ws_col;
}
#endif
size_t num_cols = header.size();
for (size_t i = 0; i < num_cols; ++i) {
widths_.emplace_back(0);
}
terminal_width = terminal_width - (2 * num_cols) - (num_cols + 1);
int avg_width = static_cast<int>(terminal_width / num_cols); // NOLINT
for (size_t i = 0; i < num_cols; ++i) {
shares_.emplace_back(avg_width);
}
InsertRow(header);
}
void TablePrinter::InsertRow(const std::vector<std::string>& row) {
std::vector<std::vector<std::string>> table_row;
size_t max_height = 0;
for (size_t i = 0; i < row.size(); ++i) {
table_row.emplace_back();
std::stringstream ss(row[i]);
std::string line;
size_t max_width = 0;
while (std::getline(ss, line, '\n')) {
table_row[i].emplace_back(line);
if (line.length() > max_width) max_width = line.length();
}
if (static_cast<float>(max_width) > widths_[i])
widths_[i] = static_cast<float>(max_width);
size_t num_lines = table_row[i].size();
if (num_lines > max_height) max_height = num_lines;
}
heights_.emplace_back(max_height);
data_.emplace_back(table_row);
}
void TablePrinter::InsetDivider() {
heights_.emplace_back(1);
data_.emplace_back();
}
void TablePrinter::CalcLayout() {
size_t field_num = widths_.size();
std::vector<size_t> idx(field_num);
std::iota(idx.begin(), idx.end(), 0);
std::stable_sort(idx.begin(), idx.end(), [this](size_t i1, size_t i2) {
return this->widths_[i1] < this->widths_[i2];
});
for (auto it = idx.begin(); it != idx.end(); ++it) {
// If a column not used all the space allocated to it
if (widths_[*it] < shares_[*it]) {
float remain = shares_[*it] - widths_[*it];
shares_[*it] -= remain;
if (it == idx.end() - 1) break;
auto next_it = it + 1;
float remain_per_column = remain / (idx.end() - next_it); // NOLINT
for (; next_it != idx.end(); ++next_it) {
shares_[*next_it] += remain_per_column;
}
}
}
for (auto& item : idx) {
shares_[item] = static_cast<size_t>(shares_[item]); // NOLINT
}
// For each record.
for (size_t i = 0; i < data_.size(); ++i) {
// For each field in the record.
for (size_t j = 0; j < data_[i].size(); ++j) {
// For each line in the field.
for (size_t line_index = 0; line_index < data_[i][j].size();
++line_index) {
std::string line = data_[i][j][line_index];
size_t num_rows =
(line.length() + shares_[j] - 1) / shares_[j]; // NOLINT
// If the number of rows required for this record is larger than 1, we
// will break that line and put it in multiple lines
if (num_rows > 1) {
data_[i][j].erase(data_[i][j].begin() + line_index); // NOLINT
for (size_t k = 0; k < num_rows; ++k) {
size_t start =
std::min(static_cast<size_t>(k * shares_[j]), // NOLINT
line.length());
size_t end =
std::min(static_cast<size_t>((k + 1) * shares_[j]), // NOLINT
line.length());
data_[i][j].insert(data_[i][j].begin() + line_index + k, // NOLINT
line.substr(start, end - start));
}
// update line_index
line_index += num_rows - 1;
}
if (heights_[i] < static_cast<float>(num_rows - 1 + data_[i][j].size()))
heights_[i] += static_cast<float>(num_rows - 1);
}
}
}
}
void TablePrinter::AddRowDivider(std::stringstream& ss) {
ss << "+";
for (float share : shares_) {
for (int j = 0; j < static_cast<int>(share) + 2; ++j) ss << "-";
ss << "+";
}
ss << "\n";
}
void TablePrinter::AddRow(std::stringstream& ss, size_t row_idx) {
auto row = data_[row_idx];
size_t max_height = static_cast<size_t>(heights_[row_idx]);
for (size_t h = 0; h < max_height; ++h) {
ss << "|" << std::left;
for (size_t i = 0; i < row.size(); ++i) {
if (h < row[i].size()) {
ss << " " << std::setw(static_cast<int>(shares_[i])) << row[i][h]
<< " |";
} else {
ss << " " << std::setw(static_cast<int>(shares_[i])) << " "
<< " |";
}
}
ss << "\n";
}
}
} // namespace paddle::inference