Updated to require C++17 and use exceptions.

This commit is contained in:
Teal Dulcet 2024-11-13 09:31:42 -08:00
parent 370dde9025
commit 8fa05e23c8
10 changed files with 182 additions and 273 deletions

View File

@ -27,7 +27,7 @@ jobs:
$CXX --version $CXX --version
- name: Script - name: Script
run: | run: |
ARGS=( -std=gnu++14 -Wall -g -Og ) ARGS=( -std=gnu++17 -Wall -g -Og )
if [[ $CXX == clang* ]]; then if [[ $CXX == clang* ]]; then
ARGS+=( -fsanitize=address,undefined,integer ) ARGS+=( -fsanitize=address,undefined,integer )
else else

View File

@ -21,7 +21,7 @@ target_sources(tglib_tables PUBLIC
# compile example binaries as executables # compile example binaries as executables
if (PROJECT_IS_TOP_LEVEL) if (PROJECT_IS_TOP_LEVEL)
set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(tglib_graphs_example "${CMAKE_CURRENT_SOURCE_DIR}/graphs.cpp") add_executable(tglib_graphs_example "${CMAKE_CURRENT_SOURCE_DIR}/graphs.cpp")
target_link_libraries(tglib_graphs_example PRIVATE tglib::graphs) target_link_libraries(tglib_graphs_example PRIVATE tglib::graphs)

View File

@ -38,13 +38,13 @@ For command-line tools using these respective libraries, see the [Tables and Gra
### Usage ### Usage
Requires support for C++14. See the [tables.hpp](tables.hpp) file for full usage information. Requires support for C++17. See the [tables.hpp](tables.hpp) file for full usage information.
Complete versions of all of the examples below and more can be found in the [tables.cpp](tables.cpp) file. Complete versions of all of the examples below and more can be found in the [tables.cpp](tables.cpp) file.
Compile with: Compile with:
* GCC: `g++ -std=c++14 -Wall -g -O3 tables.cpp -o tables` * GCC: `g++ -std=c++17 -Wall -g -O3 tables.cpp -o tables`
* Clang: `clang++ -std=c++14 -Wall -g -O3 tables.cpp -o tables` * Clang: `clang++ -std=c++17 -Wall -g -O3 tables.cpp -o tables`
Other compilers should work as well, but are not (yet) tested. Other compilers should work as well, but are not (yet) tested.
@ -68,9 +68,7 @@ int main()
// Allocate and set array // Allocate and set array
tables::options aoptions; tables::options aoptions = {.headerrow = true, .headercolumn = true};
aoptions.headerrow = true;
aoptions.headercolumn = true;
tables::array(rows, columns, array, nullptr, nullptr, aoptions); tables::array(rows, columns, array, nullptr, nullptr, aoptions);
@ -99,9 +97,7 @@ int main()
string *headerrow = nullptr; string *headerrow = nullptr;
string *headercolumn = nullptr; string *headercolumn = nullptr;
tables::options aoptions; tables::options aoptions = {.headerrow = true, .headercolumn = true};
aoptions.headerrow = true;
aoptions.headercolumn = true;
tables::array(array, headerrow, headercolumn, aoptions); tables::array(array, headerrow, headercolumn, aoptions);
@ -134,9 +130,7 @@ int main()
// Allocate and set array // Allocate and set array
tables::options aoptions; tables::options aoptions = {.headerrow = true, .headercolumn = true};
aoptions.headerrow = true;
aoptions.headercolumn = true;
tables::array(rows, columns, array, headerrow, headercolumn, aoptions); tables::array(rows, columns, array, headerrow, headercolumn, aoptions);
@ -165,11 +159,7 @@ int main()
// Set array // Set array
tables::options aoptions; tables::options aoptions = {.headerrow = true, .headercolumn = true};
aoptions.headerrow = true;
aoptions.headercolumn = true;
// or with C++20:
// tables::options aoptions{.headerrow = true, .headercolumn = true};
tables::array(array, headerrow, headercolumn, aoptions); tables::array(array, headerrow, headercolumn, aoptions);
@ -337,8 +327,7 @@ int main()
double xmax = 10; double xmax = 10;
double xstep = 0.5; double xstep = 0.5;
tables::options aoptions; tables::options aoptions = {.headerrow = true};
aoptions.headerrow = true;
tables::function(xmin, xmax, xstep, afunction, aoptions); tables::function(xmin, xmax, xstep, afunction, aoptions);
@ -362,8 +351,7 @@ int main()
function<double(double)> afunction = [](auto x) function<double(double)> afunction = [](auto x)
{ return x + 1; }; { return x + 1; };
tables::options aoptions; tables::options aoptions = {.headerrow = true};
aoptions.headerrow = true;
tables::function(xmin, xmax, xstep, afunction, aoptions); tables::function(xmin, xmax, xstep, afunction, aoptions);
@ -404,8 +392,7 @@ int main()
// Function parameter and return value can be any data type, as long as they are the same // Function parameter and return value can be any data type, as long as they are the same
function<double(double)> functions[] = {function1, function2}; function<double(double)> functions[] = {function1, function2};
tables::options aoptions; tables::options aoptions = {.headerrow = true};
aoptions.headerrow = true;
tables::functions(xmin, xmax, xstep, numfunctions, functions, aoptions); tables::functions(xmin, xmax, xstep, numfunctions, functions, aoptions);
@ -435,8 +422,7 @@ int main()
[](auto x) [](auto x)
{ return pow(x, 2); }}; { return pow(x, 2); }};
tables::options aoptions; tables::options aoptions = {.headerrow = true};
aoptions.headerrow = true;
tables::functions(xmin, xmax, xstep, numfunctions, functions, aoptions); tables::functions(xmin, xmax, xstep, numfunctions, functions, aoptions);
@ -538,13 +524,13 @@ Check that the width of the table is not greater then the width of the terminal.
### Usage ### Usage
Requires support for C++14. See the [graphs.hpp](graphs.hpp) file for full usage information. Requires support for C++17. See the [graphs.hpp](graphs.hpp) file for full usage information.
Complete versions of all of the examples below and more can be found in the [graphs.cpp](graphs.cpp) file. Complete versions of all of the examples below and more can be found in the [graphs.cpp](graphs.cpp) file.
Compile with: Compile with:
* GCC: `g++ -std=c++14 -Wall -g -O3 graphs.cpp -o graphs` * GCC: `g++ -std=c++17 -Wall -g -O3 graphs.cpp -o graphs`
* Clang: `clang++ -std=c++14 -Wall -g -O3 graphs.cpp -o graphs` * Clang: `clang++ -std=c++17 -Wall -g -O3 graphs.cpp -o graphs`
Other compilers should work as well, but are not (yet) tested. Other compilers should work as well, but are not (yet) tested.

View File

@ -1,6 +1,6 @@
// Teal Dulcet, CS546 // Teal Dulcet, CS546
// Compile: g++ -std=c++14 -Wall -g -O3 graphs.cpp -o graphs // Compile: g++ -std=gnu++17 -Wall -g -O3 graphs.cpp -o graphs
// Run: ./graphs // Run: ./graphs
@ -242,7 +242,7 @@ int main()
{ {
aoptions.style = style; aoptions.style = style;
graphs::functions(height, width, xmin, xmax, ymin, ymax, graphs::size(functions), functions, aoptions); graphs::functions(height, width, xmin, xmax, ymin, ymax, size(functions), functions, aoptions);
} }
} }
{ {
@ -257,7 +257,7 @@ int main()
{ {
aoptions.style = style; aoptions.style = style;
graphs::functions(height, width, xmin, xmax, ymin, ymax, graphs::size(functions), functions, aoptions); graphs::functions(height, width, xmin, xmax, ymin, ymax, size(functions), functions, aoptions);
} }
} }
{ {
@ -270,13 +270,13 @@ int main()
graphs::options aoptions; graphs::options aoptions;
aoptions.axisunitslabel = false; aoptions.axisunitslabel = false;
// graphs::options aoptions{.axisunitslabel = false}; // graphs::options aoptions = {.axisunitslabel = false};
for (const graphs::style_type style : graphs::style_types) for (const graphs::style_type style : graphs::style_types)
{ {
aoptions.style = style; aoptions.style = style;
graphs::functions(height, width, xmin, xmax, ymin, ymax, graphs::size(functions), functions, aoptions); graphs::functions(height, width, xmin, xmax, ymin, ymax, size(functions), functions, aoptions);
} }
/* aoptions.style = 2; /* aoptions.style = 2;
@ -286,7 +286,7 @@ int main()
cout << "\e[1;1H" cout << "\e[1;1H"
<< "\e[2J"; << "\e[2J";
graphs::functions(k, k, xmin, xmax, ymin, ymax, graphs::size(functions), functions, aoptions); graphs::functions(k, k, xmin, xmax, ymin, ymax, size(functions), functions, aoptions);
usleep(200000); usleep(200000);
} */ } */

View File

@ -168,52 +168,30 @@ namespace graphs
bool check = true; bool check = true;
}; };
template <typename T>
constexpr size_t size(const T &array)
{
return distance(cbegin(array), cend(array));
}
// Number of columns needed to represent the string // Number of columns needed to represent the string
// Adapted from: https://stackoverflow.com/a/31124065 // Adapted from: https://stackoverflow.com/a/31124065
inline int strcol(const char *const str) inline int strcol(const string &str)
{ {
size_t length = strlen(str); for (const char c : str)
for (size_t i = 0; i < length; ++i) if (iscntrl(c))
if (iscntrl(str[i]))
{ {
cerr << "\nError! Control character in string.\n"; cerr << "\nError: Control character in string.\n";
cout << "Control character: " << (int)str[i] << '\n'; cout << "Control character: " << (int)c << '\n';
} }
length = mbstowcs(nullptr, str, 0); size_t length = mbstowcs(nullptr, str.c_str(), 0);
if (length == static_cast<size_t>(-1)) if (length == static_cast<size_t>(-1))
{ throw range_error("Error: mbstowcs failed. Invalid multibyte character.");
cerr << "\nError! mbstowcs failed. Invalid multibyte character.\n";
exit(1);
}
++length; ++length;
auto *wcstring = new wchar_t[length]; wstring wcstring(length, L'\0');
if (mbstowcs(wcstring, str, length) == static_cast<size_t>(-1)) if (mbstowcs(wcstring.data(), str.c_str(), length) == static_cast<size_t>(-1))
{ throw range_error("Error: mbstowcs failed. Invalid multibyte character.");
if (wcstring)
delete[] wcstring;
cerr << "\nError! mbstowcs failed. Invalid multibyte character.\n"; const int width = wcswidth(wcstring.c_str(), length);
exit(1);
}
const int width = wcswidth(wcstring, length);
if (width == -1) if (width == -1)
{ throw range_error("Error: wcswidth failed. Nonprintable wide character.");
cerr << "\nError! wcswidth failed. Nonprintable wide character.\n";
exit(1);
}
if (wcstring)
delete[] wcstring;
return width; return width;
} }
@ -221,7 +199,7 @@ namespace graphs
// Word wrap // Word wrap
// Source: https://gist.github.com/tdulcet/819821ca69501822ad3f84a060c640a0 // Source: https://gist.github.com/tdulcet/819821ca69501822ad3f84a060c640a0
// Adapted from: https://stackoverflow.com/a/42016346 and https://stackoverflow.com/a/13094734 // Adapted from: https://stackoverflow.com/a/42016346 and https://stackoverflow.com/a/13094734
inline string wrap(const char *const str, const size_t line_length) inline string wrap(const string &str, const size_t line_length)
{ {
string words = str; string words = str;
string wrapped; string wrapped;
@ -245,9 +223,7 @@ namespace graphs
++tempindex; ++tempindex;
} }
const string temp = words.substr(index - linelen, templinelen); const size_t width = strcol(words.substr(index - linelen, templinelen));
const size_t width = strcol(temp.c_str());
if (width >= line_length) if (width >= line_length)
{ {
@ -343,7 +319,8 @@ namespace graphs
strm << setprecision(0) << fixed << number; strm << setprecision(0) << fixed << number;
} }
strm << (power < graphs::size(suffix_power_char) ? suffix_power_char[power] : "(error)"); // power == 1 and scale == units_scale_SI ? "k" :
strm << (power < size(suffix_power_char) ? suffix_power_char[power] : "(error)");
if (scale == units_scale_IEC_I and power > 0) if (scale == units_scale_IEC_I and power > 0)
strm << "i"; strm << "i";
@ -360,7 +337,7 @@ namespace graphs
long double intpart = 0; long double intpart = 0;
const long double fractionpart = abs(modf(number, &intpart)); const long double fractionpart = abs(modf(number, &intpart));
for (size_t i = 0; i < graphs::size(fractions) and !output; ++i) for (size_t i = 0; i < size(fractions) and !output; ++i)
{ {
if (abs(fractionpart - fractionvalues[i]) <= DBL_EPSILON * n) if (abs(fractionpart - fractionvalues[i]) <= DBL_EPSILON * n)
{ {
@ -377,7 +354,7 @@ namespace graphs
if (n > DBL_EPSILON) if (n > DBL_EPSILON)
{ {
for (size_t i = 0; i < graphs::size(constants) and !output; ++i) for (size_t i = 0; i < size(constants) and !output; ++i)
{ {
if (abs(fmod(number, constantvalues[i])) <= DBL_EPSILON * n) if (abs(fmod(number, constantvalues[i])) <= DBL_EPSILON * n)
{ {
@ -442,7 +419,7 @@ namespace graphs
break; break;
} }
const size_t length = strcol(strm.str().c_str()); const size_t length = strcol(strm.str());
return length; return length;
} }
@ -450,7 +427,7 @@ namespace graphs
// Output graph // Output graph
inline int graph(const size_t height, const size_t width, const long double xmin, const long double xmax, const long double ymin, const long double ymax, const vector<vector<unsigned short>> &array, const options &aoptions) inline int graph(const size_t height, const size_t width, const long double xmin, const long double xmax, const long double ymin, const long double ymax, const vector<vector<unsigned short>> &array, const options &aoptions)
{ {
if (!graphs::size(array)) if (!size(array))
return 1; return 1;
const bool border = aoptions.border; const bool border = aoptions.border;
@ -461,10 +438,10 @@ namespace graphs
const type_type type = aoptions.type; const type_type type = aoptions.type;
const char *const title = aoptions.title; const char *const title = aoptions.title;
if (height == 0) if (!height)
return 1; return 1;
if (width == 0) if (!width)
return 1; return 1;
struct winsize w; struct winsize w;
@ -580,7 +557,7 @@ namespace graphs
} }
else if (axaxis) else if (axaxis)
{ {
if (i == 0) if (!i)
{ {
cout << astyle[4]; cout << astyle[4];
output = true; output = true;
@ -611,7 +588,7 @@ namespace graphs
} }
else if (ayaxis) else if (ayaxis)
{ {
if (j == 0) if (!j)
{ {
cout << astyle[2]; cout << astyle[2];
output = true; output = true;
@ -645,7 +622,7 @@ namespace graphs
cout << '0'; cout << '0';
output = true; output = true;
} }
else if ((xaxis <= (width - aj) ? j >= (width - aj) : j == 0) and yaxislabel and axislabel) else if ((xaxis <= (width - aj) ? j >= (width - aj) : !j) and yaxislabel and axislabel)
{ {
cout << 'x'; cout << 'x';
output = true; output = true;
@ -691,7 +668,7 @@ namespace graphs
} }
} }
} }
else if ((yaxis >= ai ? i == 0 : i >= (height - ai)) and xaxislabel and axislabel) else if ((yaxis >= ai ? !i : i >= (height - ai)) and xaxislabel and axislabel)
{ {
cout << 'y'; cout << 'y';
output = true; output = true;
@ -720,7 +697,7 @@ namespace graphs
if (type == type_histogram) if (type == type_histogram)
{ {
if (!dot) if (!dot)
dot = (graphs::size(bars) - l) - 1; dot = (size(bars) - l) - 1;
} }
else if (type == type_block) else if (type == type_block)
dot += blockvalues[k][l]; dot += blockvalues[k][l];
@ -776,7 +753,7 @@ namespace graphs
template <typename T> template <typename T>
int histogram(size_t height, size_t width, long double xmin, long double xmax, long double ymin, long double ymax, const T &aarray, const options &aoptions = {}) int histogram(size_t height, size_t width, long double xmin, long double xmax, long double ymin, long double ymax, const T &aarray, const options &aoptions = {})
{ {
if (!graphs::size(aarray)) if (!size(aarray))
return 1; return 1;
const color_type color = aoptions.color; const color_type color = aoptions.color;
@ -784,10 +761,10 @@ namespace graphs
struct winsize w; struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
if (height == 0) if (!height)
height = w.ws_row * 4; height = w.ws_row * 4;
if (width == 0) if (!width)
width = w.ws_col * 2; width = w.ws_col * 2;
if (aoptions.check) if (aoptions.check)
@ -811,12 +788,12 @@ namespace graphs
height *= 2; height *= 2;
width /= 2; width /= 2;
if (xmin == 0 and xmax == 0) if (!xmin and !xmax)
{ {
const auto &minmax = minmax_element(begin(aarray), end(aarray)); const auto &[amin, amax] = minmax_element(cbegin(aarray), cend(aarray));
xmin = *minmax.first; xmin = *amin;
xmax = *minmax.second; xmax = *amax;
} }
if (xmin >= xmax) if (xmin >= xmax)
@ -838,12 +815,12 @@ namespace graphs
} }
} }
if (ymin == 0 and ymax == 0) if (!ymin and !ymax)
{ {
const auto &minmax = minmax_element(histogram.begin(), histogram.end()); const auto &[amin, amax] = minmax_element(histogram.cbegin(), histogram.cend());
ymin = *minmax.first; ymin = *amin;
ymax = *minmax.second; ymax = *amax;
} }
if (ymin >= ymax) if (ymin >= ymax)
@ -859,7 +836,7 @@ namespace graphs
const unsigned acolor = color + 1; const unsigned acolor = color + 1;
for (size_t x = 0; x < graphs::size(histogram); ++x) for (size_t x = 0; x < size(histogram); ++x)
{ {
const size_t ay = histogram[x]; const size_t ay = histogram[x];
@ -867,7 +844,8 @@ namespace graphs
aaarray[x][y] = acolor; aaarray[x][y] = acolor;
} }
if (aoptions.type != type_histogram) { if (aoptions.type != type_histogram)
{
options hist_options = aoptions; options hist_options = aoptions;
hist_options.type = type_histogram; hist_options.type = type_histogram;
return graph(height, width, xmin, xmax, ymin, ymax, aaarray, hist_options); return graph(height, width, xmin, xmax, ymin, ymax, aaarray, hist_options);
@ -878,7 +856,7 @@ namespace graphs
template <typename T> template <typename T>
int histogram(size_t height, size_t width, long double xmin, long double xmax, long double ymin, long double ymax, const size_t rows, T *aarray, const options &aoptions = {}) int histogram(size_t height, size_t width, long double xmin, long double xmax, long double ymin, long double ymax, const size_t rows, T *aarray, const options &aoptions = {})
{ {
if (rows == 0) if (!rows)
return 1; return 1;
vector<T> aaarray(rows); vector<T> aaarray(rows);
@ -891,12 +869,12 @@ namespace graphs
template <typename T> template <typename T>
int plots(size_t height, size_t width, long double xmin, long double xmax, long double ymin, long double ymax, const T &arrays, const options &aoptions = {}) int plots(size_t height, size_t width, long double xmin, long double xmax, long double ymin, long double ymax, const T &arrays, const options &aoptions = {})
{ {
if (!graphs::size(arrays)) if (!size(arrays))
return 1; return 1;
if (!all_of(cbegin(arrays), cend(arrays), [](const auto &array) if (!all_of(cbegin(arrays), cend(arrays), [](const auto &array)
{ return all_of(cbegin(array), cend(array), [](const auto &x) { return all_of(cbegin(array), cend(array), [](const auto &x)
{ return graphs::size(x) == 2; }); })) { return size(x) == 2; }); }))
{ {
cerr << "Error: The arrays must have two columns.\n"; cerr << "Error: The arrays must have two columns.\n";
return 1; return 1;
@ -907,10 +885,10 @@ namespace graphs
struct winsize w; struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
if (height == 0) if (!height)
height = w.ws_row * 4; height = w.ws_row * 4;
if (width == 0) if (!width)
width = w.ws_col * 2; width = w.ws_col * 2;
if (aoptions.check) if (aoptions.check)
@ -934,24 +912,24 @@ namespace graphs
if (aoptions.type == type_block) if (aoptions.type == type_block)
height /= 2; height /= 2;
if (xmin == 0 and xmax == 0) if (!xmin and !xmax)
{ {
const auto compare = [](const auto &a, const auto &b) const auto compare = [](const auto &a, const auto &b)
{ return a[0] < b[0]; }; { return a[0] < b[0]; };
const auto &result = accumulate(begin(arrays), end(arrays), make_pair(arrays[0][0], arrays[0][0]), [compare](const auto &current, const auto &array) const auto &[amin, amax] = accumulate(cbegin(arrays), cend(arrays), make_pair(arrays[0][0], arrays[0][0]), [&compare](const auto &current, const auto &array)
{ const auto &minmax = minmax_element(begin(array), end(array), compare); return make_pair(min(current.first, *minmax.first, compare), max(current.second, *minmax.second, compare)); }); { const auto &[amin, amax] = minmax_element(cbegin(array), cend(array), compare); return make_pair(min(current.first, *amin, compare), max(current.second, *amax, compare)); });
xmin = result.first[0]; xmin = amin[0];
xmax = result.second[0]; xmax = amax[0];
} }
if (ymin == 0 and ymax == 0) if (!ymin and !ymax)
{ {
const auto compare = [](const auto &a, const auto &b) const auto compare = [](const auto &a, const auto &b)
{ return a[1] < b[1]; }; { return a[1] < b[1]; };
const auto &result = accumulate(begin(arrays), end(arrays), make_pair(arrays[0][0], arrays[0][0]), [compare](const auto &current, const auto &array) const auto &[amin, amax] = accumulate(cbegin(arrays), cend(arrays), make_pair(arrays[0][0], arrays[0][0]), [&compare](const auto &current, const auto &array)
{ const auto &minmax = minmax_element(begin(array), end(array), compare); return make_pair(min(current.first, *minmax.first, compare), max(current.second, *minmax.second, compare)); }); { const auto &[amin, amax] = minmax_element(cbegin(array), cend(array), compare); return make_pair(min(current.first, *amin, compare), max(current.second, *amax, compare)); });
ymin = result.first[1]; ymin = amin[1];
ymax = result.second[1]; ymax = amax[1];
} }
if (xmin >= xmax) if (xmin >= xmax)
@ -973,12 +951,12 @@ namespace graphs
vector<vector<unsigned short>> aarray(width, vector<unsigned short>(height, 0)); vector<vector<unsigned short>> aarray(width, vector<unsigned short>(height, 0));
for (size_t j = 0; j < graphs::size(arrays); ++j) for (size_t j = 0; j < size(arrays); ++j)
{ {
const auto &array = arrays[j]; const auto &array = arrays[j];
const unsigned acolor = graphs::size(arrays) == 1 ? color + 1 : (j % (graphs::size(colors) - 2)) + 3; const unsigned acolor = size(arrays) == 1 ? color + 1 : (j % (size(colors) - 2)) + 3;
for (size_t i = 0; i < graphs::size(array); ++i) for (size_t i = 0; i < size(array); ++i)
{ {
const auto &x = array[i][0], &y = array[i][1]; const auto &x = array[i][0], &y = array[i][1];
@ -987,10 +965,10 @@ namespace graphs
const size_t ax = (x / xstep) + xaxis; const size_t ax = (x / xstep) + xaxis;
const size_t ay = (yaxis - (y / ystep)) - 1; const size_t ay = (yaxis - (y / ystep)) - 1;
for (const auto &mark : marks[aoptions.mark]) for (const auto &[ix, iy] : marks[aoptions.mark])
{ {
const size_t x = ax + mark[0]; const size_t x = ax + ix;
const size_t y = ay + mark[1]; const size_t y = ay + iy;
if (x < width and y < height) if (x < width and y < height)
{ {
@ -1023,7 +1001,7 @@ namespace graphs
template <typename T> template <typename T>
int plot(size_t height, size_t width, long double xmin, long double xmax, long double ymin, long double ymax, const size_t rows, T **aarray, const options &aoptions = {}) int plot(size_t height, size_t width, long double xmin, long double xmax, long double ymin, long double ymax, const size_t rows, T **aarray, const options &aoptions = {})
{ {
if (rows == 0) if (!rows)
return 1; return 1;
const size_t columns = 2; const size_t columns = 2;
@ -1040,16 +1018,16 @@ namespace graphs
{ {
const color_type color = aoptions.color; const color_type color = aoptions.color;
if (numfunctions == 0) if (!numfunctions)
return 1; return 1;
struct winsize w; struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
if (height == 0) if (!height)
height = w.ws_row * 4; height = w.ws_row * 4;
if (width == 0) if (!width)
width = w.ws_col * 2; width = w.ws_col * 2;
if (aoptions.check) if (aoptions.check)
@ -1097,7 +1075,7 @@ namespace graphs
for (size_t j = 0; j < numfunctions; ++j) for (size_t j = 0; j < numfunctions; ++j)
{ {
const unsigned short acolor = numfunctions == 1 ? color + 1 : (j % (graphs::size(colors) - 2)) + 3; const unsigned short acolor = numfunctions == 1 ? color + 1 : (j % (size(colors) - 2)) + 3;
for (size_t i = 0; i < rows * xres; ++i) for (size_t i = 0; i < rows * xres; ++i)
{ {
@ -1140,5 +1118,4 @@ namespace graphs
return functions(height, width, xmin, xmax, ymin, ymax, 1, afunctions, aoptions); return functions(height, width, xmin, xmax, ymin, ymax, 1, afunctions, aoptions);
} }
} }

View File

@ -173,10 +173,8 @@ def strcol(astr: str) -> int:
"""Returns the number of columns that the given string would take up if printed.""" """Returns the number of columns that the given string would take up if printed."""
width = wcswidth(astr) width = wcswidth(astr)
if width == -1: if width == -1:
print( msg = "wcswidth failed. Nonprintable wide character."
"\nError! wcswidth failed. Nonprintable wide character.", raise ValueError(msg)
file=sys.stderr)
sys.exit(1)
return width return width
# return len(astr) # return len(astr)
@ -305,10 +303,10 @@ def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
if not array: if not array:
return 1 return 1
if height == 0: if not height:
return 1 return 1
if width == 0: if not width:
return 1 return 1
w = shutil.get_terminal_size() w = shutil.get_terminal_size()
@ -395,7 +393,7 @@ def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
strm += astyle[6] strm += astyle[6]
output = True output = True
elif axaxis: elif axaxis:
if i == 0: if not i:
strm += astyle[4] strm += astyle[4]
output = True output = True
elif i >= height - ai: elif i >= height - ai:
@ -414,7 +412,7 @@ def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
strm += astyle[1] strm += astyle[1]
output = True output = True
elif ayaxis: elif ayaxis:
if j == 0: if not j:
strm += astyle[2] strm += astyle[2]
output = True output = True
elif j >= width - aj: elif j >= width - aj:
@ -435,7 +433,7 @@ def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
elif yaxislabel and xaxislabel and axistick and axisunitslabel and ymin <= 0 <= ymax and xmin <= 0 <= xmax: elif yaxislabel and xaxislabel and axistick and axisunitslabel and ymin <= 0 <= ymax and xmin <= 0 <= xmax:
strm += "0" strm += "0"
output = True output = True
elif (j >= width - aj if xaxis <= width - aj else j == 0) and yaxislabel and axislabel: elif (j >= width - aj if xaxis <= width - aj else not j) and yaxislabel and axislabel:
strm += "x" strm += "x"
output = True output = True
elif yaxislabel and axistick and axisunitslabel: elif yaxislabel and axistick and axisunitslabel:
@ -470,7 +468,7 @@ def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
output = True output = True
else: else:
j += aj j += aj
elif (i == 0 if yaxis >= ai else i >= height - ai) and xaxislabel and axislabel: elif (not i if yaxis >= ai else i >= height - ai) and xaxislabel and axislabel:
strm += "y" strm += "y"
output = True output = True
elif ylabellength and (xaxislabel if xaxis < aj else j < xaxis - ylabellength and j + aj >= xaxis - ylabellength) and (yaxis >= ai or i < height - ai) and axistick and axisunitslabel: elif ylabellength and (xaxislabel if xaxis < aj else j < xaxis - ylabellength and j + aj >= xaxis - ylabellength) and (yaxis >= ai or i < height - ai) and axistick and axisunitslabel:
@ -535,10 +533,10 @@ def histogram(height: int, width: int, xmin: float, xmax: float, ymin: float, ym
w = shutil.get_terminal_size() w = shutil.get_terminal_size()
if height == 0: if not height:
height = w.lines * 4 height = w.lines * 4
if width == 0: if not width:
width = w.columns * 2 width = w.columns * 2
if check: if check:
@ -558,7 +556,7 @@ def histogram(height: int, width: int, xmin: float, xmax: float, ymin: float, ym
height *= 2 height *= 2
width //= 2 width //= 2
if xmin == xmax == 0: if not xmin and not xmax:
xmin = min(aarray) xmin = min(aarray)
xmax = max(aarray) xmax = max(aarray)
@ -575,7 +573,7 @@ def histogram(height: int, width: int, xmin: float, xmax: float, ymin: float, ym
index = int((x - xmin) / xstep) index = int((x - xmin) / xstep)
histogram[index] += 1 histogram[index] += 1
if ymin == ymax == 0: if not ymin and not ymax:
ymin = min(histogram) ymin = min(histogram)
ymax = max(histogram) ymax = max(histogram)
@ -610,10 +608,10 @@ def plots(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
w = shutil.get_terminal_size() w = shutil.get_terminal_size()
if height == 0: if not height:
height = w.lines * 4 height = w.lines * 4
if width == 0: if not width:
width = w.columns * 2 width = w.columns * 2
if check: if check:
@ -633,11 +631,11 @@ def plots(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax:
if atype == type_types.block: if atype == type_types.block:
height //= 2 height //= 2
if xmin == xmax == 0: if not xmin and not xmax:
xmin = min(x for aarray in aarrays for x, y in aarray) xmin = min(x for aarray in aarrays for x, y in aarray)
xmax = max(x for aarray in aarrays for x, y in aarray) xmax = max(x for aarray in aarrays for x, y in aarray)
if ymin == ymax == 0: if not ymin and not ymax:
ymin = min(y for aarray in aarrays for x, y in aarray) ymin = min(y for aarray in aarrays for x, y in aarray)
ymax = max(y for aarray in aarrays for x, y in aarray) ymax = max(y for aarray in aarrays for x, y in aarray)
@ -690,10 +688,10 @@ def functions(height: int, width: int, xmin: float, xmax: float, ymin: float, ym
w = shutil.get_terminal_size() w = shutil.get_terminal_size()
if height == 0: if not height:
height = w.lines * 4 height = w.lines * 4
if width == 0: if not width:
width = w.columns * 2 width = w.columns * 2
if check: if check:

View File

@ -59,10 +59,8 @@ def strcol(astr: str) -> int:
astr = ansi.sub("", astr) astr = ansi.sub("", astr)
width = wcswidth(astr) width = wcswidth(astr)
if width == -1: if width == -1:
print( msg = "wcswidth failed. Nonprintable wide character."
"\nError! wcswidth failed. Nonprintable wide character.", raise ValueError(msg)
file=sys.stderr)
sys.exit(1)
return width return width
# return len(astr) # return len(astr)
@ -106,7 +104,7 @@ def table(array: List[List[str]], headerrow: bool = False, headercolumn: bool =
strm += astyle[0] * (2 * padding + columnwidth[j]) strm += astyle[0] * (2 * padding + columnwidth[j])
if j < columns - 1: if j < columns - 1:
if cellborder or headerrow or (j == 0 and headercolumn): if cellborder or headerrow or (not j and headercolumn):
strm += astyle[3] strm += astyle[3]
else: else:
strm += astyle[0] strm += astyle[0]
@ -118,14 +116,14 @@ def table(array: List[List[str]], headerrow: bool = False, headercolumn: bool =
strm += astyle[1] strm += astyle[1]
for j in range(columns): for j in range(columns):
if (j > 0 and cellborder) or (i == 0 and j > 0 and headerrow) or (j == 1 and headercolumn): if (j > 0 and cellborder) or (not i and j > 0 and headerrow) or (j == 1 and headercolumn):
strm += astyle[1] strm += astyle[1]
elif j > 0 and (tableborder or (i > 0 and headerrow) or headercolumn): elif j > 0 and (tableborder or (i > 0 and headerrow) or headercolumn):
strm += " " strm += " "
awidth = columnwidth[j] - (strcol(array[i][j]) - len(array[i][j])) awidth = columnwidth[j] - (strcol(array[i][j]) - len(array[i][j]))
if (i == 0 and headerrow) or (j == 0 and headercolumn): if (not i and headerrow) or (not j and headercolumn):
strm += (" " * padding) + "\033[1m" + array[i][j].center(awidth) + "\033[22m" + (" " * padding) strm += (" " * padding) + "\033[1m" + array[i][j].center(awidth) + "\033[22m" + (" " * padding)
else: else:
strm += (" " * padding) + (f"{array[i][j]:{awidth}}" if alignment is None else array[i][j].rjust(awidth) if alignment else array[i][j].ljust(awidth)) + (" " * padding) strm += (" " * padding) + (f"{array[i][j]:{awidth}}" if alignment is None else array[i][j].rjust(awidth) if alignment else array[i][j].ljust(awidth)) + (" " * padding)
@ -136,29 +134,29 @@ def table(array: List[List[str]], headerrow: bool = False, headercolumn: bool =
if i < rows - 1 or tableborder: if i < rows - 1 or tableborder:
strm += "\n" strm += "\n"
if (i < rows - 1 and cellborder) or (i == 0 and headerrow) or (i < rows - 1 and headercolumn): if (i < rows - 1 and cellborder) or (not i and headerrow) or (i < rows - 1 and headercolumn):
if tableborder and (cellborder or (i == 0 and headerrow) or headercolumn): if tableborder and (cellborder or (not i and headerrow) or headercolumn):
strm += astyle[5] strm += astyle[5]
for j in range(columns): for j in range(columns):
if cellborder or (i == 0 and headerrow) or (j == 0 and headercolumn): if cellborder or (not i and headerrow) or (not j and headercolumn):
strm += astyle[0] * (2 * padding + columnwidth[j]) strm += astyle[0] * (2 * padding + columnwidth[j])
elif headercolumn: elif headercolumn:
strm += " " * (2 * padding + columnwidth[j]) strm += " " * (2 * padding + columnwidth[j])
if j < columns - 1: if j < columns - 1:
if cellborder or ((i == 0 and headerrow) and (j == 0 and headercolumn)): if cellborder or ((not i and headerrow) and (not j and headercolumn)):
strm += astyle[6] strm += astyle[6]
elif i == 0 and headerrow: elif not i and headerrow:
strm += astyle[9] strm += astyle[9]
elif headercolumn: elif headercolumn:
if j == 0: if not j:
strm += astyle[7] strm += astyle[7]
else: else:
strm += " " strm += " "
if tableborder: if tableborder:
if cellborder or (i == 0 and headerrow): if cellborder or (not i and headerrow):
strm += astyle[7] strm += astyle[7]
elif headercolumn: elif headercolumn:
strm += astyle[1] strm += astyle[1]
@ -172,7 +170,7 @@ def table(array: List[List[str]], headerrow: bool = False, headercolumn: bool =
strm += astyle[0] * (2 * padding + columnwidth[j]) strm += astyle[0] * (2 * padding + columnwidth[j])
if j < columns - 1: if j < columns - 1:
if cellborder or (j == 0 and headercolumn): if cellborder or (not j and headercolumn):
strm += astyle[9] strm += astyle[9]
else: else:
strm += astyle[0] strm += astyle[0]

View File

@ -5,6 +5,7 @@
# Run: python3 -OO test.py # Run: python3 -OO test.py
import math import math
import operator
import random import random
import sys import sys
@ -87,7 +88,7 @@ print("\nOutput sorted array as table\n")
array = ([random.randint(0, sys.maxsize) array = ([random.randint(0, sys.maxsize)
for j in range(columns)] for i in range(rows)) for j in range(columns)] for i in range(rows))
sortdimension = 0 sortdimension = 0
array = sorted(array, key=lambda x: x[sortdimension]) array = sorted(array, key=operator.itemgetter(sortdimension))
for style in tables.style_types: for style in tables.style_types:
tables.array(array, None, None, style=style) tables.array(array, None, None, style=style)

View File

@ -1,6 +1,6 @@
// Teal Dulcet, CS546 // Teal Dulcet, CS546
// Compile: g++ -std=c++14 -Wall -g -O3 tables.cpp -o tables // Compile: g++ -std=gnu++17 -Wall -g -O3 tables.cpp -o tables
// Run: ./tables // Run: ./tables
@ -216,7 +216,7 @@ int main()
tables::options aoptions; tables::options aoptions;
aoptions.headerrow = true; aoptions.headerrow = true;
aoptions.headercolumn = true; aoptions.headercolumn = true;
// tables::options aoptions{.headerrow = true, .headercolumn = true}; // tables::options aoptions = {.headerrow = true, .headercolumn = true};
for (const tables::style_type style : tables::style_types) for (const tables::style_type style : tables::style_types)
{ {
@ -232,10 +232,7 @@ int main()
{"Header column 4", "Data 9", "Data 10", "Data 11", "Data 12"}, {"Header column 4", "Data 9", "Data 10", "Data 11", "Data 12"},
{"Header column 5", "Data 13", "Data 14", "Data 15", "Data 16"}}}; {"Header column 5", "Data 13", "Data 14", "Data 15", "Data 16"}}};
tables::options aoptions; tables::options aoptions = {.headerrow = true, .headercolumn = true};
aoptions.headerrow = true;
aoptions.headercolumn = true;
// tables::options aoptions{.headerrow = true, .headercolumn = true};
for (const tables::style_type style : tables::style_types) for (const tables::style_type style : tables::style_types)
{ {
@ -259,10 +256,7 @@ int main()
const char *const headerrow[] = {"Header row/column 1", "Header row 2", "Header row 3", "Header row 4", "Header row 5"}; const char *const headerrow[] = {"Header row/column 1", "Header row 2", "Header row 3", "Header row 4", "Header row 5"};
const char *const headercolumn[] = {"Header column 2", "Header column 3", "Header column 4", "Header column 5"}; const char *const headercolumn[] = {"Header column 2", "Header column 3", "Header column 4", "Header column 5"};
tables::options aoptions; tables::options aoptions = {.headerrow = true, .headercolumn = true};
aoptions.headerrow = true;
aoptions.headercolumn = true;
// tables::options aoptions{.headerrow = true, .headercolumn = true};
for (const tables::style_type style : tables::style_types) for (const tables::style_type style : tables::style_types)
{ {
@ -295,7 +289,7 @@ int main()
aoptions.headercolumn = true; aoptions.headercolumn = true;
aoptions.cellborder = true; aoptions.cellborder = true;
aoptions.style = style; aoptions.style = style;
// tables::options aoptions{.headerrow = true, .headercolumn = true, .cellborder = true, .style = style}; // tables::options aoptions = {.headerrow = true, .headercolumn = true, .cellborder = true, .style = style};
tables::array(aarray, headerrow, headercolumn, aoptions); tables::array(aarray, headerrow, headercolumn, aoptions);
} }
@ -304,7 +298,7 @@ int main()
aoptions.headerrow = true; aoptions.headerrow = true;
aoptions.headercolumn = true; aoptions.headercolumn = true;
aoptions.style = style; aoptions.style = style;
// tables::options aoptions{.headerrow = true, .headercolumn = true, .style = style}; // tables::options aoptions = {.headerrow = true, .headercolumn = true, .style = style};
tables::array(aarray, headerrow, headercolumn, aoptions); tables::array(aarray, headerrow, headercolumn, aoptions);
} }
@ -315,7 +309,7 @@ int main()
tables::options aoptions; tables::options aoptions;
aoptions.headerrow = true; aoptions.headerrow = true;
aoptions.style = style; aoptions.style = style;
// tables::options aoptions{.headerrow = true, .style = style}; // tables::options aoptions = {.headerrow = true, .style = style};
tables::array(aarray, headerrow, headercolumn, aoptions); tables::array(aarray, headerrow, headercolumn, aoptions);
} }
@ -326,7 +320,7 @@ int main()
tables::options aoptions; tables::options aoptions;
aoptions.headercolumn = true; aoptions.headercolumn = true;
aoptions.style = style; aoptions.style = style;
// tables::options aoptions{.headercolumn = true, .style = style}; // tables::options aoptions = {.headercolumn = true, .style = style};
tables::array(aarray, headerrow, headercolumn, aoptions); tables::array(aarray, headerrow, headercolumn, aoptions);
} }
@ -337,7 +331,7 @@ int main()
tables::options aoptions; tables::options aoptions;
aoptions.cellborder = true; aoptions.cellborder = true;
aoptions.style = style; aoptions.style = style;
// tables::options aoptions{.cellborder = true, .style = style}; // tables::options aoptions = {.cellborder = true, .style = style};
tables::array(aarray, headerrow, headercolumn, aoptions); tables::array(aarray, headerrow, headercolumn, aoptions);
} }
@ -348,7 +342,7 @@ int main()
tables::options aoptions; tables::options aoptions;
aoptions.tableborder = false; aoptions.tableborder = false;
aoptions.style = style; aoptions.style = style;
// tables::options aoptions{.tableborder = false, .style = style}; // tables::options aoptions = {.tableborder = false, .style = style};
tables::array(aarray, headerrow, headercolumn, aoptions); tables::array(aarray, headerrow, headercolumn, aoptions);
} }
@ -358,7 +352,7 @@ int main()
aoptions.headerrow = true; aoptions.headerrow = true;
aoptions.headercolumn = true; aoptions.headercolumn = true;
aoptions.style = style; aoptions.style = style;
// tables::options aoptions{.tableborder = false, .headerrow = true, .headercolumn = true, .style = style}; // tables::options aoptions = {.tableborder = false, .headerrow = true, .headercolumn = true, .style = style};
tables::array(aarray, headerrow, headercolumn, aoptions); tables::array(aarray, headerrow, headercolumn, aoptions);
} }
@ -370,7 +364,7 @@ int main()
aoptions.tableborder = false; aoptions.tableborder = false;
aoptions.headerrow = true; aoptions.headerrow = true;
aoptions.style = style; aoptions.style = style;
// tables::options aoptions{.tableborder = false, .headerrow = true, .style = style}; // tables::options aoptions = {.tableborder = false, .headerrow = true, .style = style};
tables::array(aarray, headerrow, headercolumn, aoptions); tables::array(aarray, headerrow, headercolumn, aoptions);
} }
@ -382,7 +376,7 @@ int main()
aoptions.tableborder = false; aoptions.tableborder = false;
aoptions.headercolumn = true; aoptions.headercolumn = true;
aoptions.style = style; aoptions.style = style;
// tables::options aoptions{.tableborder = false, .headercolumn = true, .style = style}; // tables::options aoptions = {.tableborder = false, .headercolumn = true, .style = style};
tables::array(aarray, headerrow, headercolumn, aoptions); tables::array(aarray, headerrow, headercolumn, aoptions);
} }
@ -394,7 +388,7 @@ int main()
aoptions.tableborder = false; aoptions.tableborder = false;
aoptions.cellborder = true; aoptions.cellborder = true;
aoptions.style = style; aoptions.style = style;
// tables::options aoptions{.tableborder = false, .cellborder = true, .style = style}; // tables::options aoptions = {.tableborder = false, .cellborder = true, .style = style};
tables::array(aarray, headerrow, headercolumn, aoptions); tables::array(aarray, headerrow, headercolumn, aoptions);
} }
@ -412,7 +406,7 @@ int main()
tables::options aoptions; tables::options aoptions;
aoptions.boolalpha = true; aoptions.boolalpha = true;
// tables::options aoptions{.boolalpha = true}; // tables::options aoptions = {.boolalpha = true};
for (const tables::style_type style : tables::style_types) for (const tables::style_type style : tables::style_types)
{ {
@ -509,9 +503,7 @@ int main()
// Output single function as table // Output single function as table
cout << "\nOutput single function as table\n\n"; cout << "\nOutput single function as table\n\n";
{ {
tables::options aoptions; tables::options aoptions = {.headerrow = true};
aoptions.headerrow = true;
// tables::options aoptions{.headerrow = true};
for (const tables::style_type style : tables::style_types) for (const tables::style_type style : tables::style_types)
{ {
@ -524,9 +516,7 @@ int main()
const function<long double(long double)> afunction = [](auto x) const function<long double(long double)> afunction = [](auto x)
{ return x + 1; }; { return x + 1; };
tables::options aoptions; tables::options aoptions = {.headerrow = true};
aoptions.headerrow = true;
// tables::options aoptions{.headerrow = true};
for (const tables::style_type style : tables::style_types) for (const tables::style_type style : tables::style_types)
{ {
@ -540,15 +530,13 @@ int main()
{ {
function<long double(long double)> functions[] = {function1, function2}; function<long double(long double)> functions[] = {function1, function2};
tables::options aoptions; tables::options aoptions = {.headerrow = true};
aoptions.headerrow = true;
// tables::options aoptions{.headerrow = true};
for (const tables::style_type style : tables::style_types) for (const tables::style_type style : tables::style_types)
{ {
aoptions.style = style; aoptions.style = style;
tables::functions(xmin, xmax, xstep, tables::size(functions), functions, aoptions); tables::functions(xmin, xmax, xstep, size(functions), functions, aoptions);
} }
} }
{ {
@ -557,15 +545,13 @@ int main()
[](auto x) [](auto x)
{ return pow(x, 2); }}; { return pow(x, 2); }};
tables::options aoptions; tables::options aoptions = {.headerrow = true};
aoptions.headerrow = true;
// tables::options aoptions{.headerrow = true};
for (const tables::style_type style : tables::style_types) for (const tables::style_type style : tables::style_types)
{ {
aoptions.style = style; aoptions.style = style;
tables::functions(xmin, xmax, xstep, tables::size(functions), functions, aoptions); tables::functions(xmin, xmax, xstep, size(functions), functions, aoptions);
} }
} }

View File

@ -65,55 +65,33 @@ namespace tables
bool check = true; bool check = true;
}; };
template <typename T>
constexpr size_t size(const T &array)
{
return distance(cbegin(array), cend(array));
}
// Number of columns needed to represent the string // Number of columns needed to represent the string
// Adapted from: https://stackoverflow.com/a/31124065 // Adapted from: https://stackoverflow.com/a/31124065
inline int strcol(const char *str) inline int strcol(const string &astr)
{ {
const string astr = regex_replace(str, ansi, ""); const string str = regex_replace(astr, ansi, "");
str = astr.c_str();
size_t length = strlen(str); for (const char c : str)
for (size_t i = 0; i < length; ++i) if (iscntrl(c))
if (iscntrl(str[i]))
{ {
cerr << "\nError! Control character in string.\n"; cerr << "\nError: Control character in string.\n";
cout << "Control character: " << (int)str[i] << '\n'; cout << "Control character: " << (int)c << '\n';
} }
length = mbstowcs(nullptr, str, 0); size_t length = mbstowcs(nullptr, str.c_str(), 0);
if (length == static_cast<size_t>(-1)) if (length == static_cast<size_t>(-1))
{ throw range_error("Error: mbstowcs failed. Invalid multibyte character.");
cerr << "\nError! mbstowcs failed. Invalid multibyte character.\n";
exit(1);
}
++length; ++length;
auto *wcstring = new wchar_t[length]; wstring wcstring(length, L'\0');
if (mbstowcs(wcstring, str, length) == static_cast<size_t>(-1)) if (mbstowcs(wcstring.data(), str.c_str(), length) == static_cast<size_t>(-1))
{ throw range_error("Error: mbstowcs failed. Invalid multibyte character.");
if (wcstring)
delete[] wcstring;
cerr << "\nError! mbstowcs failed. Invalid multibyte character.\n"; const int width = wcswidth(wcstring.c_str(), length);
exit(1);
}
const int width = wcswidth(wcstring, length);
if (width == -1) if (width == -1)
{ throw range_error("Error: wcswidth failed. Nonprintable wide character.");
cerr << "\nError! wcswidth failed. Nonprintable wide character.\n";
exit(1);
}
if (wcstring)
delete[] wcstring;
return width; return width;
} }
@ -121,7 +99,7 @@ namespace tables
// Word wrap // Word wrap
// Source: https://gist.github.com/tdulcet/819821ca69501822ad3f84a060c640a0 // Source: https://gist.github.com/tdulcet/819821ca69501822ad3f84a060c640a0
// Adapted from: https://stackoverflow.com/a/42016346 and https://stackoverflow.com/a/13094734 // Adapted from: https://stackoverflow.com/a/42016346 and https://stackoverflow.com/a/13094734
inline string wrap(const char *const str, const size_t line_length) inline string wrap(const string &str, const size_t line_length)
{ {
string words = str; string words = str;
string wrapped; string wrapped;
@ -145,9 +123,7 @@ namespace tables
++tempindex; ++tempindex;
} }
const string temp = words.substr(index - linelen, templinelen); const size_t width = strcol(words.substr(index - linelen, templinelen));
const size_t width = strcol(temp.c_str());
if (width >= line_length) if (width >= line_length)
{ {
@ -171,7 +147,7 @@ namespace tables
template <typename T> template <typename T>
int table(const vector<vector<basic_string<T>>> &array, const options &aoptions) int table(const vector<vector<basic_string<T>>> &array, const options &aoptions)
{ {
if (!tables::size(array)) if (!size(array))
return 1; return 1;
const bool headerrow = aoptions.headerrow; const bool headerrow = aoptions.headerrow;
@ -192,7 +168,7 @@ namespace tables
{ {
for (size_t i = 0; i < rows; ++i) for (size_t i = 0; i < rows; ++i)
{ {
const int cellwidth = strcol(array[i][j].c_str()); const int cellwidth = strcol(array[i][j]);
if (cellwidth > columnwidth[j]) if (cellwidth > columnwidth[j])
columnwidth[j] = cellwidth; columnwidth[j] = cellwidth;
} }
@ -236,7 +212,7 @@ namespace tables
if (j < (columns - 1)) if (j < (columns - 1))
{ {
if (cellborder or headerrow or (j == 0 and headercolumn)) if (cellborder or headerrow or (!j and headercolumn))
cout << astyle[3]; cout << astyle[3];
else else
cout << astyle[0]; cout << astyle[0];
@ -253,14 +229,14 @@ namespace tables
for (size_t j = 0; j < columns; ++j) for (size_t j = 0; j < columns; ++j)
{ {
if ((j and cellborder) or (i == 0 and j and headerrow) or (j == 1 and headercolumn)) if ((j and cellborder) or (!i and j and headerrow) or (j == 1 and headercolumn))
cout << astyle[1]; cout << astyle[1];
else if (j and (tableborder or (i and headerrow) or headercolumn)) else if (j and (tableborder or (i and headerrow) or headercolumn))
cout << ' '; cout << ' ';
const int difference = columnwidth[j] - strcol(array[i][j].c_str()); const int difference = columnwidth[j] - strcol(array[i][j]);
if ((i == 0 and headerrow) or (j == 0 and headercolumn)) if ((!i and headerrow) or (!j and headercolumn))
{ {
const int apadding = (difference / 2); const int apadding = (difference / 2);
@ -278,17 +254,17 @@ namespace tables
if (i < (rows - 1) or tableborder) if (i < (rows - 1) or tableborder)
cout << '\n'; cout << '\n';
if ((i < (rows - 1) and cellborder) or (i == 0 and headerrow) or (i < (rows - 1) and headercolumn)) if ((i < (rows - 1) and cellborder) or (!i and headerrow) or (i < (rows - 1) and headercolumn))
{ {
if (tableborder) if (tableborder)
{ {
if (cellborder or (i == 0 and headerrow) or headercolumn) if (cellborder or (!i and headerrow) or headercolumn)
cout << astyle[5]; cout << astyle[5];
} }
for (size_t j = 0; j < columns; ++j) for (size_t j = 0; j < columns; ++j)
{ {
if (cellborder or (i == 0 and headerrow) or (j == 0 and headercolumn)) if (cellborder or (!i and headerrow) or (!j and headercolumn))
for (size_t k = 0; k < (2 * padding) + columnwidth[j]; ++k) for (size_t k = 0; k < (2 * padding) + columnwidth[j]; ++k)
cout << astyle[0]; cout << astyle[0];
else if (headercolumn) else if (headercolumn)
@ -296,13 +272,13 @@ namespace tables
if (j < (columns - 1)) if (j < (columns - 1))
{ {
if (cellborder or ((i == 0 and headerrow) and (j == 0 and headercolumn))) if (cellborder or ((!i and headerrow) and (!j and headercolumn)))
cout << astyle[6]; cout << astyle[6];
else if (i == 0 and headerrow) else if (!i and headerrow)
cout << astyle[9]; cout << astyle[9];
else if (headercolumn) else if (headercolumn)
{ {
if (j == 0) if (!j)
cout << astyle[7]; cout << astyle[7];
else else
cout << ' '; cout << ' ';
@ -312,7 +288,7 @@ namespace tables
if (tableborder) if (tableborder)
{ {
if (cellborder or (i == 0 and headerrow)) if (cellborder or (!i and headerrow))
cout << astyle[7]; cout << astyle[7];
else if (headercolumn) else if (headercolumn)
cout << astyle[1]; cout << astyle[1];
@ -333,7 +309,7 @@ namespace tables
if (j < (columns - 1)) if (j < (columns - 1))
{ {
if (cellborder or (j == 0 and headercolumn)) if (cellborder or (!j and headercolumn))
cout << astyle[9]; cout << astyle[9];
else else
cout << astyle[0]; cout << astyle[0];
@ -352,17 +328,17 @@ namespace tables
template <typename T1, typename T2> template <typename T1, typename T2>
int array(const T1 &aarray, T2 headerrow[] = nullptr, T2 headercolumn[] = nullptr, const options &aoptions = {}) int array(const T1 &aarray, T2 headerrow[] = nullptr, T2 headercolumn[] = nullptr, const options &aoptions = {})
{ {
if (!tables::size(aarray)) if (!size(aarray))
return 1; return 1;
size_t i = 0; size_t i = 0;
size_t j = 0; size_t j = 0;
size_t rows = tables::size(aarray); size_t rows = size(aarray);
size_t columns = tables::size(aarray[0]); size_t columns = size(aarray[0]);
if (!all_of(cbegin(aarray), cend(aarray), [&columns](const auto &x) if (!all_of(cbegin(aarray), cend(aarray), [&columns](const auto &x)
{ return tables::size(x) == columns; })) { return size(x) == columns; }))
{ {
cerr << "Error: The rows of the array must have the same number of columns.\n"; cerr << "Error: The rows of the array must have the same number of columns.\n";
return 1; return 1;
@ -460,7 +436,7 @@ namespace tables
template <typename T> template <typename T>
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 = {}) 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 = {})
{ {
if (numfunctions == 0) if (!numfunctions)
return 1; return 1;
if (xmin >= xmax) if (xmin >= xmax)
@ -481,9 +457,9 @@ namespace tables
const char *const aheaderrow[] = {"x", "y"}; const char *const aheaderrow[] = {"x", "y"};
// const char* const aheaderrow[] = {"", "x", "y"}; // const char* const aheaderrow[] = {"", "x", "y"};
const size_t length = tables::size(aheaderrow); const size_t length = size(aheaderrow);
auto *headerrow = new string[columns]; vector<string> headerrow(columns);
for (size_t j = 0; j < columns; ++j) for (size_t j = 0; j < columns; ++j)
{ {
@ -500,7 +476,7 @@ namespace tables
} }
string *headercolumn = nullptr; string *headercolumn = nullptr;
// headercolumn = new string[rows + 1]; // vector<string> headercolumn(rows + 1);
// for (size_t i = 0; i < rows + 1; ++i) // for (size_t i = 0; i < rows + 1; ++i)
// { // {
@ -519,19 +495,7 @@ namespace tables
aarray[i][j + 1] = (functions[j])(aarray[i][0]); aarray[i][j + 1] = (functions[j])(aarray[i][0]);
} }
const int code = array(aarray, headerrow, headercolumn, aoptions); return array(aarray, headerrow.data(), headercolumn, aoptions);
if (headerrow)
{
delete[] headerrow;
}
// if (headercolumn)
// {
// delete[] headercolumn;
// }
return code;
} }
// Convert single function to array and output as table // Convert single function to array and output as table
@ -551,5 +515,4 @@ namespace tables
return functions(xmin, xmax, xstep, 1, afunctions, aoptions); return functions(xmin, xmax, xstep, 1, afunctions, aoptions);
} }
} }