1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef INPUT_TABLE_DUMP_H
17 #define INPUT_TABLE_DUMP_H
18 
19 #include <iomanip>
20 #include <iostream>
21 #include <sstream>
22 #include <string>
23 #include <tuple>
24 #include <vector>
25 
26 namespace OHOS {
27 namespace MMI {
28 constexpr size_t EXTRA_CHARACTERS_COUNT { 3 };
29 constexpr int32_t ELEMENT_SPACE_COUNT { 2 };
30 
31 template<typename T>
getElementLength(const T & element)32 inline size_t getElementLength(const T &element)
33 {
34     std::ostringstream oss;
35     oss << element;
36     return oss.str().size();
37 }
38 
39 template<typename... Titles, typename... Args>
CalculateColumnWidths(const std::tuple<Titles...> & titles,const std::vector<std::tuple<Args...>> & rows,size_t & lineWidth)40 inline std::vector<size_t> CalculateColumnWidths(const std::tuple<Titles...> &titles,
41                                                  const std::vector<std::tuple<Args...>> &rows,
42                                                  size_t &lineWidth)
43 {
44     std::vector<size_t> widths(sizeof...(Titles), 0);
45     auto updateWidths = [&widths](const auto &... field) {
46         size_t index = 0;
47         ((widths[index] = std::max(widths[index], getElementLength(field)), ++index), ...);
48     };
49     std::apply(updateWidths, titles);
50     for (const auto &row: rows) {
51         std::apply(updateWidths, row);
52     }
53     std::for_each(widths.begin(), widths.end(),
54                   [&lineWidth](size_t width) { lineWidth += width + EXTRA_CHARACTERS_COUNT; });
55     lineWidth += 1;
56     return widths;
57 }
58 
PrintLine(std::ostream & os,const std::vector<size_t> & widths)59 inline void PrintLine(std::ostream &os, const std::vector<size_t> &widths)
60 {
61     os << "+";
62     for (const size_t &width: widths) {
63         os << std::setw(static_cast<int32_t>(width) + ELEMENT_SPACE_COUNT) << std::left << std::setfill('-')
64            << "" << "+";
65     }
66     os << std::setfill(' ') << std::endl;
67 }
68 
69 template<typename T>
PrintCentered(std::ostream & os,const T & value,size_t width)70 inline void PrintCentered(std::ostream &os, const T &value, size_t width)
71 {
72     std::ostringstream oss;
73     oss << value;
74     std::string str = oss.str();
75     size_t padding_left = (width - str.size()) / 2;
76     size_t padding_right = width - str.size() - padding_left;
77     os << std::string(padding_left, ' ') << str << std::string(padding_right, ' ');
78 }
79 
80 template<typename... Titles>
PrintHeader(std::ostream & os,const std::vector<size_t> & widths,Titles...titles)81 inline void PrintHeader(std::ostream &os, const std::vector<size_t> &widths, Titles... titles)
82 {
83     os << "|";
84     size_t index = 0;
85     ((os << " ", PrintCentered(os, titles, widths[index++]), os << " |"), ...);
86     os << std::endl;
87 }
88 
89 template<typename... Args>
PrintRow(std::ostream & os,const std::vector<size_t> & widths,Args...args)90 inline void PrintRow(std::ostream &os, const std::vector<size_t> &widths, Args... args)
91 {
92     os << "|";
93     size_t index = 0;
94     ((os << " ", PrintCentered(os, args, widths[index++]), os << " |"), ...);
95     os << std::endl;
96 }
97 
98 template<typename... Titles, typename... Args>
DumpFullTable(std::ostream & os,const std::string & tableName,const std::tuple<Titles...> & titles,const std::vector<std::tuple<Args...>> & rows)99 inline void DumpFullTable(std::ostream &os, const std::string &tableName, const std::tuple<Titles...> &titles,
100                           const std::vector<std::tuple<Args...>> &rows)
101 {
102     static_assert(sizeof...(Titles) == sizeof...(Args), "Number of titles must match number of columns in each row");
103 
104     // 计算每一列的最大宽度
105     size_t lineWidth = 0;
106     std::vector<size_t> widths = CalculateColumnWidths(titles, rows, lineWidth);
107 
108     // 打印表名称
109     PrintCentered(os, tableName, lineWidth);
110     os << std::endl;
111 
112     // 打印标题行
113     PrintLine(os, widths);
114     std::apply([&os, &widths](auto &&... args) { PrintHeader(os, widths, args...); }, titles);
115     PrintLine(os, widths);
116 
117     // 打印每一行数据
118     for (const auto &row: rows) {
119         std::apply([&os, &widths](auto &&... args) { PrintRow(os, widths, args...); }, row);
120         PrintLine(os, widths);
121     }
122 }
123 } // namespace MMI
124 } // namespace OHOS
125 #endif //INPUT_TABLE_DUMP_H
126