2019-01-04 17:29:55 +08:00
|
|
|
// Teal Dulcet, CS546
|
2024-11-13 01:17:12 +08:00
|
|
|
#pragma once
|
2019-01-04 17:29:55 +08:00
|
|
|
#include <iostream>
|
|
|
|
#include <sstream>
|
|
|
|
#include <cstring>
|
|
|
|
#include <iomanip>
|
|
|
|
#include <cwchar>
|
|
|
|
#include <clocale>
|
2019-01-04 17:50:15 +08:00
|
|
|
#include <cstdlib>
|
2022-07-14 16:33:38 +08:00
|
|
|
#include <vector>
|
|
|
|
#include <iterator>
|
2023-03-10 21:15:01 +08:00
|
|
|
#include <numeric>
|
2019-01-04 17:29:55 +08:00
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <unistd.h>
|
2022-07-14 16:33:38 +08:00
|
|
|
#include <regex>
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2024-11-13 01:17:12 +08:00
|
|
|
#ifdef TGLIB_TABLES_NAMESPACE
|
|
|
|
namespace TGLIB_TABLES_NAMESPACE
|
|
|
|
{
|
|
|
|
#else
|
2022-07-14 16:44:17 +08:00
|
|
|
namespace tables
|
2019-01-04 17:29:55 +08:00
|
|
|
{
|
2024-11-13 01:17:12 +08:00
|
|
|
#endif
|
2022-07-14 16:44:17 +08:00
|
|
|
using namespace std;
|
|
|
|
|
2023-03-10 21:15:01 +08:00
|
|
|
enum style_type
|
|
|
|
{
|
|
|
|
style_ASCII,
|
|
|
|
style_basic,
|
|
|
|
style_light,
|
|
|
|
style_heavy,
|
|
|
|
style_double,
|
2023-08-30 20:57:03 +08:00
|
|
|
style_arc,
|
2023-03-10 21:15:01 +08:00
|
|
|
style_light_dashed,
|
|
|
|
style_heavy_dashed
|
|
|
|
};
|
|
|
|
|
2023-08-30 20:57:03 +08:00
|
|
|
enum style_type const style_types[] = {style_ASCII, style_basic, style_light, style_heavy, style_double, style_arc, style_light_dashed, style_heavy_dashed};
|
2023-03-10 21:15:01 +08:00
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
const char *const styles[][11] = {
|
|
|
|
{"-", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"}, // ASCII
|
|
|
|
{"—", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"}, // Basic
|
|
|
|
{"─", "│", "┌", "┬", "┐", "├", "┼", "┤", "└", "┴", "┘"}, // Light
|
|
|
|
{"━", "┃", "┏", "┳", "┓", "┣", "╋", "┫", "┗", "┻", "┛"}, // Heavy
|
|
|
|
{"═", "║", "╔", "╦", "╗", "╠", "╬", "╣", "╚", "╩", "╝"}, // Double
|
2023-08-30 20:57:03 +08:00
|
|
|
{"─", "│", "╭", "┬", "╮", "├", "┼", "┤", "╰", "┴", "╯"}, // Light Arc
|
2023-03-13 22:29:43 +08:00
|
|
|
{"╌", "┊", "┌", "┬", "┐", "├", "┼", "┤", "└", "┴", "┘"}, // Light Dashed
|
|
|
|
{"╍", "┋", "┏", "┳", "┓", "┣", "╋", "┫", "┗", "┻", "┛"} // Heavy Dashed
|
|
|
|
// {" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "} // No border
|
2022-07-14 16:44:17 +08:00
|
|
|
};
|
|
|
|
|
2023-03-10 21:15:01 +08:00
|
|
|
const regex ansi(R"(\x1B\[(?:[0-9]+(?:;[0-9]+)*)?m)");
|
2022-07-14 16:44:17 +08:00
|
|
|
|
|
|
|
struct options
|
|
|
|
{
|
|
|
|
bool headerrow = false;
|
|
|
|
bool headercolumn = false;
|
|
|
|
bool tableborder = true;
|
|
|
|
bool cellborder = false;
|
2023-09-01 20:54:13 +08:00
|
|
|
unsigned padding = 1;
|
2022-07-14 16:44:17 +08:00
|
|
|
ios_base &(*alignment)(ios_base &) = left;
|
|
|
|
bool boolalpha = false;
|
|
|
|
const char *title = nullptr;
|
2023-03-10 21:15:01 +08:00
|
|
|
style_type style = style_light;
|
|
|
|
bool check = true;
|
2022-07-14 16:44:17 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
// Number of columns needed to represent the string
|
|
|
|
// Adapted from: https://stackoverflow.com/a/31124065
|
2024-11-14 01:31:42 +08:00
|
|
|
inline int strcol(const string &astr)
|
2022-07-14 16:44:17 +08:00
|
|
|
{
|
2024-11-14 01:31:42 +08:00
|
|
|
const string str = regex_replace(astr, ansi, "");
|
2022-07-14 16:44:17 +08:00
|
|
|
|
2024-11-14 01:31:42 +08:00
|
|
|
for (const char c : str)
|
|
|
|
if (iscntrl(c))
|
2022-07-14 16:44:17 +08:00
|
|
|
{
|
2024-11-14 01:31:42 +08:00
|
|
|
cerr << "\nError: Control character in string.\n";
|
|
|
|
cout << "Control character: " << (int)c << '\n';
|
2022-07-14 16:44:17 +08:00
|
|
|
}
|
2022-07-14 16:33:38 +08:00
|
|
|
|
2024-11-14 01:31:42 +08:00
|
|
|
size_t length = mbstowcs(nullptr, str.c_str(), 0);
|
2022-07-14 16:44:17 +08:00
|
|
|
if (length == static_cast<size_t>(-1))
|
2024-11-14 01:31:42 +08:00
|
|
|
throw range_error("Error: mbstowcs failed. Invalid multibyte character.");
|
2022-07-14 16:44:17 +08:00
|
|
|
++length;
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2024-11-14 01:31:42 +08:00
|
|
|
wstring wcstring(length, L'\0');
|
2022-07-14 16:44:17 +08:00
|
|
|
|
2024-11-14 01:31:42 +08:00
|
|
|
if (mbstowcs(wcstring.data(), str.c_str(), length) == static_cast<size_t>(-1))
|
|
|
|
throw range_error("Error: mbstowcs failed. Invalid multibyte character.");
|
2022-07-14 16:44:17 +08:00
|
|
|
|
2024-11-14 01:31:42 +08:00
|
|
|
const int width = wcswidth(wcstring.c_str(), length);
|
2022-07-14 16:44:17 +08:00
|
|
|
if (width == -1)
|
2024-11-14 01:31:42 +08:00
|
|
|
throw range_error("Error: wcswidth failed. Nonprintable wide character.");
|
2019-01-04 17:29:55 +08:00
|
|
|
|
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
return width;
|
2019-01-04 17:29:55 +08:00
|
|
|
}
|
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
// Word wrap
|
|
|
|
// Source: https://gist.github.com/tdulcet/819821ca69501822ad3f84a060c640a0
|
|
|
|
// Adapted from: https://stackoverflow.com/a/42016346 and https://stackoverflow.com/a/13094734
|
2024-11-14 01:31:42 +08:00
|
|
|
inline string wrap(const string &str, const size_t line_length)
|
2019-01-04 17:29:55 +08:00
|
|
|
{
|
2023-03-10 21:15:01 +08:00
|
|
|
string words = str;
|
2022-07-14 16:44:17 +08:00
|
|
|
string wrapped;
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
size_t index = 0;
|
|
|
|
size_t linelen = 0;
|
|
|
|
while (words[index] != '\0')
|
2019-01-04 17:29:55 +08:00
|
|
|
{
|
2022-07-14 16:44:17 +08:00
|
|
|
if (words[index] == '\n')
|
2019-01-04 17:29:55 +08:00
|
|
|
{
|
2022-07-14 16:44:17 +08:00
|
|
|
linelen = 0;
|
2019-01-04 17:29:55 +08:00
|
|
|
}
|
2022-07-14 16:44:17 +08:00
|
|
|
else if (isspace(words[index]))
|
|
|
|
{
|
|
|
|
size_t tempindex = index + 1;
|
|
|
|
size_t templinelen = linelen;
|
|
|
|
while (!isspace(words[tempindex]) and words[tempindex] != '\0')
|
|
|
|
{
|
|
|
|
++templinelen;
|
|
|
|
|
|
|
|
++tempindex;
|
|
|
|
}
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2024-11-14 01:31:42 +08:00
|
|
|
const size_t width = strcol(words.substr(index - linelen, templinelen));
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
if (width >= line_length)
|
|
|
|
{
|
|
|
|
words[index] = '\n';
|
|
|
|
linelen = 0;
|
|
|
|
}
|
2019-01-04 17:29:55 +08:00
|
|
|
}
|
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
if (words[index] == '\t')
|
|
|
|
linelen += 8 - (linelen % 8);
|
|
|
|
else if (words[index] != '\n')
|
|
|
|
++linelen;
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
++index;
|
|
|
|
}
|
|
|
|
wrapped = words;
|
|
|
|
return wrapped;
|
2019-01-04 17:29:55 +08:00
|
|
|
}
|
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
// Output char array as table
|
|
|
|
template <typename T>
|
|
|
|
int table(const vector<vector<basic_string<T>>> &array, const options &aoptions)
|
|
|
|
{
|
2024-11-14 01:31:42 +08:00
|
|
|
if (!size(array))
|
2022-07-14 16:44:17 +08:00
|
|
|
return 1;
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
const bool headerrow = aoptions.headerrow;
|
|
|
|
const bool headercolumn = aoptions.headercolumn;
|
|
|
|
const bool tableborder = aoptions.tableborder;
|
|
|
|
const bool cellborder = aoptions.cellborder;
|
2023-09-01 20:54:13 +08:00
|
|
|
const unsigned padding = aoptions.padding;
|
2022-07-14 16:44:17 +08:00
|
|
|
const char *const title = aoptions.title;
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
const size_t rows = array.size();
|
|
|
|
const size_t columns = array[0].size();
|
2022-07-14 16:33:38 +08:00
|
|
|
|
2024-06-01 23:59:28 +08:00
|
|
|
vector<int> columnwidth(columns);
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2023-03-10 21:15:01 +08:00
|
|
|
setlocale(LC_ALL, "");
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2023-03-10 21:15:01 +08:00
|
|
|
for (size_t j = 0; j < columns; ++j)
|
2019-01-04 17:29:55 +08:00
|
|
|
{
|
2023-03-10 21:15:01 +08:00
|
|
|
for (size_t i = 0; i < rows; ++i)
|
2022-07-14 16:44:17 +08:00
|
|
|
{
|
2024-11-14 01:31:42 +08:00
|
|
|
const int cellwidth = strcol(array[i][j]);
|
2022-07-14 16:44:17 +08:00
|
|
|
if (cellwidth > columnwidth[j])
|
|
|
|
columnwidth[j] = cellwidth;
|
|
|
|
}
|
|
|
|
}
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
struct winsize w;
|
|
|
|
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2024-06-01 23:59:28 +08:00
|
|
|
size_t width = accumulate(columnwidth.cbegin(), columnwidth.cend(), 0ul);
|
2023-03-10 21:15:01 +08:00
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
if (tableborder or cellborder or headerrow or headercolumn)
|
|
|
|
width += (((2 * padding) + 1) * columns) + (tableborder ? 1 : -1);
|
|
|
|
else
|
|
|
|
width += (2 * padding) * columns;
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2023-03-10 21:15:01 +08:00
|
|
|
if (aoptions.check)
|
2022-07-14 16:44:17 +08:00
|
|
|
{
|
2023-03-10 21:15:01 +08:00
|
|
|
if (width > w.ws_col)
|
|
|
|
{
|
|
|
|
cerr << "The width of the table (" << width << ") is greater then the width of the terminal (" << w.ws_col << ").\n";
|
|
|
|
return 1;
|
|
|
|
}
|
2022-07-14 16:44:17 +08:00
|
|
|
}
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2023-03-10 21:15:01 +08:00
|
|
|
if (title and title[0] != '\0')
|
2023-05-11 22:03:53 +08:00
|
|
|
cout << wrap(title, width) << '\n';
|
2023-03-10 21:15:01 +08:00
|
|
|
|
|
|
|
if (aoptions.alignment)
|
|
|
|
cout << aoptions.alignment;
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2023-12-31 23:57:30 +08:00
|
|
|
const char *const *astyle = styles[aoptions.style];
|
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
if (tableborder)
|
2019-01-04 17:29:55 +08:00
|
|
|
{
|
2023-12-31 23:57:30 +08:00
|
|
|
cout << astyle[2];
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2023-03-10 21:15:01 +08:00
|
|
|
for (size_t j = 0; j < columns; ++j)
|
2022-07-14 16:44:17 +08:00
|
|
|
{
|
2023-03-10 21:15:01 +08:00
|
|
|
for (size_t k = 0; k < (2 * padding) + columnwidth[j]; ++k)
|
2023-12-31 23:57:30 +08:00
|
|
|
cout << astyle[0];
|
2022-07-14 16:44:17 +08:00
|
|
|
|
2023-03-10 21:15:01 +08:00
|
|
|
if (j < (columns - 1))
|
|
|
|
{
|
2024-11-14 01:31:42 +08:00
|
|
|
if (cellborder or headerrow or (!j and headercolumn))
|
2023-12-31 23:57:30 +08:00
|
|
|
cout << astyle[3];
|
2023-03-10 21:15:01 +08:00
|
|
|
else
|
2023-12-31 23:57:30 +08:00
|
|
|
cout << astyle[0];
|
2023-03-10 21:15:01 +08:00
|
|
|
}
|
2022-07-14 16:44:17 +08:00
|
|
|
}
|
2023-03-10 21:15:01 +08:00
|
|
|
|
2023-12-31 23:57:30 +08:00
|
|
|
cout << astyle[4] << '\n';
|
2019-01-04 17:29:55 +08:00
|
|
|
}
|
|
|
|
|
2023-03-10 21:15:01 +08:00
|
|
|
for (size_t i = 0; i < rows; ++i)
|
2019-01-04 17:29:55 +08:00
|
|
|
{
|
2023-03-10 21:15:01 +08:00
|
|
|
if (tableborder)
|
2023-12-31 23:57:30 +08:00
|
|
|
cout << astyle[1];
|
2023-03-10 21:15:01 +08:00
|
|
|
|
|
|
|
for (size_t j = 0; j < columns; ++j)
|
2022-07-14 16:44:17 +08:00
|
|
|
{
|
2024-11-14 01:31:42 +08:00
|
|
|
if ((j and cellborder) or (!i and j and headerrow) or (j == 1 and headercolumn))
|
2023-12-31 23:57:30 +08:00
|
|
|
cout << astyle[1];
|
2023-03-10 21:15:01 +08:00
|
|
|
else if (j and (tableborder or (i and headerrow) or headercolumn))
|
2023-05-11 22:03:53 +08:00
|
|
|
cout << ' ';
|
2021-09-14 18:03:02 +08:00
|
|
|
|
2024-11-14 01:31:42 +08:00
|
|
|
const int difference = columnwidth[j] - strcol(array[i][j]);
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2024-11-14 01:31:42 +08:00
|
|
|
if ((!i and headerrow) or (!j and headercolumn))
|
2022-07-14 16:44:17 +08:00
|
|
|
{
|
|
|
|
const int apadding = (difference / 2);
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2023-12-31 23:57:30 +08:00
|
|
|
cout << string(padding + apadding, ' ') << "\e[1m" << array[i][j] << "\e[22m" << string(padding + (difference - apadding), ' ');
|
2022-07-14 16:44:17 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-12-31 23:57:30 +08:00
|
|
|
cout << string(padding, ' ') << setw(difference + array[i][j].length()) << array[i][j] << string(padding, ' ');
|
2022-07-14 16:44:17 +08:00
|
|
|
}
|
2019-01-04 17:29:55 +08:00
|
|
|
}
|
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
if (tableborder)
|
2023-12-31 23:57:30 +08:00
|
|
|
cout << astyle[1];
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2023-03-13 22:29:43 +08:00
|
|
|
if (i < (rows - 1) or tableborder)
|
2023-05-11 22:03:53 +08:00
|
|
|
cout << '\n';
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2024-11-14 01:31:42 +08:00
|
|
|
if ((i < (rows - 1) and cellborder) or (!i and headerrow) or (i < (rows - 1) and headercolumn))
|
2019-01-04 17:29:55 +08:00
|
|
|
{
|
2023-05-11 22:03:53 +08:00
|
|
|
if (tableborder)
|
|
|
|
{
|
2024-11-14 01:31:42 +08:00
|
|
|
if (cellborder or (!i and headerrow) or headercolumn)
|
2023-12-31 23:57:30 +08:00
|
|
|
cout << astyle[5];
|
2023-05-11 22:03:53 +08:00
|
|
|
}
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2023-03-10 21:15:01 +08:00
|
|
|
for (size_t j = 0; j < columns; ++j)
|
2019-01-04 17:29:55 +08:00
|
|
|
{
|
2024-11-14 01:31:42 +08:00
|
|
|
if (cellborder or (!i and headerrow) or (!j and headercolumn))
|
2023-03-10 21:15:01 +08:00
|
|
|
for (size_t k = 0; k < (2 * padding) + columnwidth[j]; ++k)
|
2023-12-31 23:57:30 +08:00
|
|
|
cout << astyle[0];
|
2023-05-11 22:03:53 +08:00
|
|
|
else if (headercolumn)
|
2022-07-14 16:44:17 +08:00
|
|
|
cout << string((2 * padding) + columnwidth[j], ' ');
|
2021-09-14 18:03:02 +08:00
|
|
|
|
2023-03-10 21:15:01 +08:00
|
|
|
if (j < (columns - 1))
|
2019-01-04 17:29:55 +08:00
|
|
|
{
|
2024-11-14 01:31:42 +08:00
|
|
|
if (cellborder or ((!i and headerrow) and (!j and headercolumn)))
|
2023-12-31 23:57:30 +08:00
|
|
|
cout << astyle[6];
|
2024-11-14 01:31:42 +08:00
|
|
|
else if (!i and headerrow)
|
2023-12-31 23:57:30 +08:00
|
|
|
cout << astyle[9];
|
2023-05-11 22:03:53 +08:00
|
|
|
else if (headercolumn)
|
2022-07-14 16:44:17 +08:00
|
|
|
{
|
2024-11-14 01:31:42 +08:00
|
|
|
if (!j)
|
2023-12-31 23:57:30 +08:00
|
|
|
cout << astyle[7];
|
2022-07-14 16:44:17 +08:00
|
|
|
else
|
2023-05-11 22:03:53 +08:00
|
|
|
cout << ' ';
|
2022-07-14 16:44:17 +08:00
|
|
|
}
|
2019-01-04 17:29:55 +08:00
|
|
|
}
|
|
|
|
}
|
2023-03-10 21:15:01 +08:00
|
|
|
|
|
|
|
if (tableborder)
|
|
|
|
{
|
2024-11-14 01:31:42 +08:00
|
|
|
if (cellborder or (!i and headerrow))
|
2023-12-31 23:57:30 +08:00
|
|
|
cout << astyle[7];
|
2023-03-10 21:15:01 +08:00
|
|
|
else if (headercolumn)
|
2023-12-31 23:57:30 +08:00
|
|
|
cout << astyle[1];
|
2023-03-10 21:15:01 +08:00
|
|
|
}
|
|
|
|
|
2023-05-11 22:03:53 +08:00
|
|
|
cout << '\n';
|
2019-01-04 17:29:55 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-11 22:03:53 +08:00
|
|
|
if (tableborder)
|
|
|
|
{
|
2023-12-31 23:57:30 +08:00
|
|
|
cout << astyle[8];
|
2023-05-11 22:03:53 +08:00
|
|
|
|
|
|
|
for (size_t j = 0; j < columns; ++j)
|
|
|
|
{
|
|
|
|
for (size_t k = 0; k < (2 * padding) + columnwidth[j]; ++k)
|
2023-12-31 23:57:30 +08:00
|
|
|
cout << astyle[0];
|
2023-05-11 22:03:53 +08:00
|
|
|
|
|
|
|
if (j < (columns - 1))
|
|
|
|
{
|
2024-11-14 01:31:42 +08:00
|
|
|
if (cellborder or (!j and headercolumn))
|
2023-12-31 23:57:30 +08:00
|
|
|
cout << astyle[9];
|
2023-05-11 22:03:53 +08:00
|
|
|
else
|
2023-12-31 23:57:30 +08:00
|
|
|
cout << astyle[0];
|
2023-05-11 22:03:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-31 23:57:30 +08:00
|
|
|
cout << astyle[10];
|
2023-05-11 22:03:53 +08:00
|
|
|
}
|
|
|
|
|
2024-06-01 23:59:28 +08:00
|
|
|
cout << '\n';
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
return 0;
|
2022-07-14 16:33:38 +08:00
|
|
|
}
|
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
// Convert array to char array and output as table
|
|
|
|
template <typename T1, typename T2>
|
2024-11-14 00:58:53 +08:00
|
|
|
int array(const T1 &aarray, T2 headerrow[] = nullptr, T2 headercolumn[] = nullptr, const options &aoptions = {})
|
2022-07-14 16:44:17 +08:00
|
|
|
{
|
2024-11-14 01:31:42 +08:00
|
|
|
if (!size(aarray))
|
2022-07-14 16:44:17 +08:00
|
|
|
return 1;
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2023-03-10 21:15:01 +08:00
|
|
|
size_t i = 0;
|
|
|
|
size_t j = 0;
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2024-11-14 01:31:42 +08:00
|
|
|
size_t rows = size(aarray);
|
|
|
|
size_t columns = size(aarray[0]);
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2024-06-01 23:59:28 +08:00
|
|
|
if (!all_of(cbegin(aarray), cend(aarray), [&columns](const auto &x)
|
2024-11-14 01:31:42 +08:00
|
|
|
{ return size(x) == columns; }))
|
2019-01-04 17:29:55 +08:00
|
|
|
{
|
2023-03-10 21:15:01 +08:00
|
|
|
cerr << "Error: The rows of the array must have the same number of columns.\n";
|
2022-07-14 16:44:17 +08:00
|
|
|
return 1;
|
2019-01-04 17:29:55 +08:00
|
|
|
}
|
|
|
|
|
2023-03-10 21:15:01 +08:00
|
|
|
if (headerrow)
|
2022-07-14 16:44:17 +08:00
|
|
|
++rows;
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2023-03-10 21:15:01 +08:00
|
|
|
if (headercolumn)
|
2022-07-14 16:44:17 +08:00
|
|
|
++columns;
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
vector<vector<string>> aaarray(rows, vector<string>(columns));
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2023-03-10 21:15:01 +08:00
|
|
|
if (headerrow)
|
2022-07-14 16:44:17 +08:00
|
|
|
{
|
2023-03-10 21:15:01 +08:00
|
|
|
for (size_t j = 0; j < columns; ++j)
|
2022-07-14 16:44:17 +08:00
|
|
|
{
|
|
|
|
aaarray[i][j] = headerrow[j];
|
|
|
|
}
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
++i;
|
2019-01-04 17:29:55 +08:00
|
|
|
}
|
|
|
|
|
2023-03-10 21:15:01 +08:00
|
|
|
for (size_t ii = 0; i < rows; ++i)
|
2019-01-04 17:29:55 +08:00
|
|
|
{
|
2023-03-10 21:15:01 +08:00
|
|
|
if (headercolumn)
|
2022-07-14 16:44:17 +08:00
|
|
|
{
|
2023-03-10 21:15:01 +08:00
|
|
|
size_t ii = i;
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2023-03-10 21:15:01 +08:00
|
|
|
if (headerrow)
|
2022-07-14 16:44:17 +08:00
|
|
|
--ii;
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
aaarray[i][j] = headercolumn[ii];
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
++j;
|
|
|
|
}
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2023-03-10 21:15:01 +08:00
|
|
|
for (size_t jj = 0; j < columns; ++j)
|
2022-07-14 16:44:17 +08:00
|
|
|
{
|
|
|
|
ostringstream strm;
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
if (aoptions.boolalpha)
|
|
|
|
strm << boolalpha;
|
2022-07-14 16:33:38 +08:00
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
strm << aarray[ii][jj];
|
|
|
|
aaarray[i][j] = strm.str();
|
2022-07-14 16:33:38 +08:00
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
++jj;
|
|
|
|
}
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
j = 0;
|
|
|
|
++ii;
|
|
|
|
}
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
return table(aaarray, aoptions);
|
2022-07-14 16:33:38 +08:00
|
|
|
}
|
2022-07-14 16:44:17 +08:00
|
|
|
|
|
|
|
template <typename T>
|
2024-11-14 00:58:53 +08:00
|
|
|
int array(const size_t rows, const size_t columns, T **aarray, const char *const headerrow[] = nullptr, const char *const headercolumn[] = nullptr, const options &aoptions = {})
|
2022-07-14 16:33:38 +08:00
|
|
|
{
|
2022-07-14 16:44:17 +08:00
|
|
|
vector<vector<T>> aaarray(rows, vector<T>(columns));
|
2023-03-10 21:15:01 +08:00
|
|
|
for (size_t i = 0; i < rows; ++i)
|
2022-07-14 16:44:17 +08:00
|
|
|
copy(aarray[i], aarray[i] + columns, aaarray[i].begin());
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
string *aheaderrow = nullptr;
|
|
|
|
string *aheadercolumn = nullptr;
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
if (headerrow and headercolumn)
|
|
|
|
{
|
|
|
|
vector<string> aaheaderrow(rows + 1);
|
|
|
|
copy(headerrow, headerrow + rows + 1, aaheaderrow.begin());
|
|
|
|
aheaderrow = aaheaderrow.data();
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
vector<string> aaheadercolumn(columns);
|
|
|
|
copy(headercolumn, headercolumn + columns, aaheadercolumn.begin());
|
|
|
|
aheadercolumn = aaheadercolumn.data();
|
|
|
|
}
|
|
|
|
else if (headerrow)
|
|
|
|
{
|
|
|
|
vector<string> aaheaderrow(rows);
|
|
|
|
copy(headerrow, headerrow + rows, aaheaderrow.begin());
|
|
|
|
aheaderrow = aaheaderrow.data();
|
|
|
|
}
|
|
|
|
else if (headercolumn)
|
|
|
|
{
|
|
|
|
vector<string> aaheadercolumn(columns);
|
|
|
|
copy(headercolumn, headercolumn + columns, aaheadercolumn.begin());
|
|
|
|
aheadercolumn = aaheadercolumn.data();
|
|
|
|
}
|
|
|
|
|
|
|
|
return array(aaarray, aheaderrow, aheadercolumn, aoptions);
|
2019-01-04 17:29:55 +08:00
|
|
|
}
|
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
// Convert one or more functions to array and output as table
|
|
|
|
template <typename T>
|
2024-11-14 00:58:53 +08:00
|
|
|
int functions(const long double xmin, const long double xmax, const long double xstep, const size_t numfunctions, function<T(T)> functions[], const options &aoptions = {})
|
2019-01-04 17:29:55 +08:00
|
|
|
{
|
2024-11-14 01:31:42 +08:00
|
|
|
if (!numfunctions)
|
2022-07-14 16:44:17 +08:00
|
|
|
return 1;
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
if (xmin >= xmax)
|
|
|
|
{
|
|
|
|
cerr << "xmin must be less than xmax.\n";
|
|
|
|
return 1;
|
|
|
|
}
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2023-03-10 21:15:01 +08:00
|
|
|
if (xstep <= 0)
|
2022-07-14 16:44:17 +08:00
|
|
|
{
|
2023-03-10 21:15:01 +08:00
|
|
|
cerr << "xstep must be greater than zero.\n";
|
2022-07-14 16:44:17 +08:00
|
|
|
return 1;
|
|
|
|
}
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2023-03-10 21:15:01 +08:00
|
|
|
const size_t rows = ((xmax - xmin) / xstep) + 1;
|
2022-07-14 16:44:17 +08:00
|
|
|
const size_t columns = numfunctions + 1;
|
2021-09-14 18:03:02 +08:00
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
const char *const aheaderrow[] = {"x", "y"};
|
|
|
|
// const char* const aheaderrow[] = {"", "x", "y"};
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2024-11-14 01:31:42 +08:00
|
|
|
const size_t length = size(aheaderrow);
|
2022-07-14 16:44:17 +08:00
|
|
|
|
2024-11-14 01:31:42 +08:00
|
|
|
vector<string> headerrow(columns);
|
2022-07-14 16:44:17 +08:00
|
|
|
|
2023-03-10 21:15:01 +08:00
|
|
|
for (size_t j = 0; j < columns; ++j)
|
2019-01-04 17:29:55 +08:00
|
|
|
{
|
2022-07-14 16:44:17 +08:00
|
|
|
if (j < (length - 1) or numfunctions == 1)
|
|
|
|
{
|
|
|
|
headerrow[j] = aheaderrow[j];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ostringstream strm;
|
|
|
|
strm << aheaderrow[length - 1] << j - length + 2;
|
|
|
|
headerrow[j] = strm.str();
|
|
|
|
}
|
2019-01-04 17:29:55 +08:00
|
|
|
}
|
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
string *headercolumn = nullptr;
|
2024-11-14 01:31:42 +08:00
|
|
|
// vector<string> headercolumn(rows + 1);
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2023-03-10 21:15:01 +08:00
|
|
|
// for (size_t i = 0; i < rows + 1; ++i)
|
2022-07-14 16:44:17 +08:00
|
|
|
// {
|
|
|
|
// ostringstream strm;
|
|
|
|
// strm << i + 1;
|
|
|
|
// headercolumn[i] = strm.str();
|
|
|
|
// }
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
vector<vector<T>> aarray(rows, vector<T>(columns));
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2023-03-10 21:15:01 +08:00
|
|
|
for (size_t i = 0; i < rows; ++i)
|
2022-07-14 16:44:17 +08:00
|
|
|
{
|
2023-03-10 21:15:01 +08:00
|
|
|
aarray[i][0] = (i * xstep) + xmin;
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2023-03-10 21:15:01 +08:00
|
|
|
for (size_t j = 0; j < numfunctions; ++j)
|
2022-07-14 16:44:17 +08:00
|
|
|
aarray[i][j + 1] = (functions[j])(aarray[i][0]);
|
|
|
|
}
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2024-11-14 01:31:42 +08:00
|
|
|
return array(aarray, headerrow.data(), headercolumn, aoptions);
|
2022-07-14 16:44:17 +08:00
|
|
|
}
|
2019-01-04 17:29:55 +08:00
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
// Convert single function to array and output as table
|
|
|
|
template <typename T>
|
2024-11-14 00:58:53 +08:00
|
|
|
int function(const long double xmin, const long double xmax, const long double xstep, const function<T(T)> &afunction, const options &aoptions = {})
|
2022-07-14 16:44:17 +08:00
|
|
|
{
|
|
|
|
std::function<T(T)> afunctions[] = {afunction};
|
2022-07-14 16:33:38 +08:00
|
|
|
|
2023-03-10 21:15:01 +08:00
|
|
|
return functions(xmin, xmax, xstep, 1, afunctions, aoptions);
|
2022-07-14 16:44:17 +08:00
|
|
|
}
|
2022-07-14 16:33:38 +08:00
|
|
|
|
2022-07-14 16:44:17 +08:00
|
|
|
// Convert single function to array and output as table
|
|
|
|
template <typename T>
|
2024-11-14 00:58:53 +08:00
|
|
|
int function(const long double xmin, const long double xmax, const long double xstep, T afunction(T), const options &aoptions = {})
|
2022-07-14 16:44:17 +08:00
|
|
|
{
|
|
|
|
std::function<T(T)> afunctions[] = {afunction};
|
|
|
|
|
2023-03-10 21:15:01 +08:00
|
|
|
return functions(xmin, xmax, xstep, 1, afunctions, aoptions);
|
2022-07-14 16:44:17 +08:00
|
|
|
}
|
2019-01-04 17:29:55 +08:00
|
|
|
}
|