| /** |
| Copyright (c) 2014 Alex Tsui |
| |
| Permission is hereby granted, free of charge, to any person obtaining a copy |
| of this software and associated documentation files (the "Software"), to deal |
| in the Software without restriction, including without limitation the rights |
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| copies of the Software, and to permit persons to whom the Software is |
| furnished to do so, subject to the following conditions: |
| |
| The above copyright notice and this permission notice shall be included in |
| all copies or substantial portions of the Software. |
| |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| THE SOFTWARE. |
| */ |
| #include "ColumnFormatter.h" |
| #include <iomanip> |
| #include <iostream> |
| #include <list> |
| #include <string> |
| #include <sstream> |
| #include <fstream> |
| #include <vector> |
| #include <cstdlib> |
| |
| bool ColumnFormatter::load(const std::string& fn) |
| { |
| items.clear(); |
| std::ifstream ifs(fn.c_str()); |
| if (!ifs.is_open()) |
| return false; |
| std::string str; |
| while (!ifs.eof()) |
| { |
| std::getline( ifs, str ); |
| if (!ifs.eof()) |
| items.push_back(str); |
| } |
| return true; |
| } |
| |
| int ColumnFormatter::solve(int width) |
| { |
| bool fits = true; |
| int i = 1; |
| while (fits) |
| { |
| ++i; |
| std::vector<size_t> widths = divideItems(i); |
| size_t columnWidth = width / i; |
| for (size_t j = 0; j < widths.size(); ++j) |
| { |
| fits &= (widths[j] < columnWidth); |
| } |
| if (!fits) |
| { |
| --i; |
| } |
| } |
| return i; |
| } |
| |
| std::vector<size_t> ColumnFormatter::divideItems(int numColumns) |
| { |
| columns.clear(); |
| for (int i = 0; i < numColumns; ++i) |
| columns.push_back(std::list<std::string>()); |
| for (size_t i = 0; i < items.size(); ++i) |
| { |
| columns[i % numColumns].push_back(items[i]); |
| } |
| |
| // count the fattest item in each column |
| std::vector<size_t> res(numColumns); |
| for (int i = 0; i < numColumns; ++i) |
| { |
| for (std::list<std::string>::const_iterator it = |
| columns[i].begin(); it != columns[i].end(); ++it) |
| { |
| if (res[i] < it->size()) |
| res[i] = it->size(); |
| } |
| } |
| |
| return res; |
| } |
| |
| void ColumnFormatter::format(int width) |
| { |
| m_formattedOutput.clear(); |
| int cols = solve(width); |
| std::vector<int> colWidths(cols, width / cols); |
| int rem = width % cols; |
| for (int i = 0; i < rem; ++i) |
| { |
| colWidths[i]++; |
| } |
| divideItems(cols); |
| std::vector< std::list<std::string>::const_iterator > its; |
| std::vector< std::list<std::string>::const_iterator > it_ends; |
| for (size_t i = 0; i < columns.size(); ++i) |
| { |
| its.push_back(columns[i].begin()); |
| it_ends.push_back(columns[i].end()); |
| } |
| bool done = false; |
| while (!done) |
| { |
| std::stringstream row_ss; |
| for (size_t i = 0; i < columns.size(); ++i) |
| { |
| std::stringstream item_ss; |
| std::string item; |
| if (its[i] != it_ends[i]) |
| { |
| item = *its[i]; |
| ++its[i]; |
| } |
| item_ss << std::left << std::setw(colWidths[i]) << item; |
| row_ss << item_ss.str(); |
| } |
| m_formattedOutput.push_back(row_ss.str()); |
| |
| done = true; |
| for (size_t i = 0; i < columns.size(); ++i) |
| { |
| done &= (its[i] == it_ends[i]); |
| } |
| } |
| } |
| |
| const std::list<std::string>& ColumnFormatter::formattedOutput() const |
| { |
| return m_formattedOutput; |
| } |