From 8fa05e23c81e7078df75e6fcafd8562ab7f2ee1e Mon Sep 17 00:00:00 2001 From: Teal Dulcet Date: Wed, 13 Nov 2024 09:31:42 -0800 Subject: [PATCH] Updated to require C++17 and use exceptions. --- .github/workflows/ci.yml | 2 +- CMakeLists.txt | 2 +- README.md | 42 ++++------- graphs.cpp | 12 +-- graphs.hpp | 159 +++++++++++++++++---------------------- python/graphs.py | 38 +++++----- python/tables.py | 28 ++++--- python/test.py | 3 +- tables.cpp | 56 ++++++-------- tables.hpp | 113 ++++++++++------------------ 10 files changed, 182 insertions(+), 273 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f27d39f..fcc1d69 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,7 +27,7 @@ jobs: $CXX --version - name: Script run: | - ARGS=( -std=gnu++14 -Wall -g -Og ) + ARGS=( -std=gnu++17 -Wall -g -Og ) if [[ $CXX == clang* ]]; then ARGS+=( -fsanitize=address,undefined,integer ) else diff --git a/CMakeLists.txt b/CMakeLists.txt index 364a138..9ec68c2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,7 @@ target_sources(tglib_tables PUBLIC # compile example binaries as executables if (PROJECT_IS_TOP_LEVEL) - set(CMAKE_CXX_STANDARD 14) + set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) add_executable(tglib_graphs_example "${CMAKE_CURRENT_SOURCE_DIR}/graphs.cpp") target_link_libraries(tglib_graphs_example PRIVATE tglib::graphs) diff --git a/README.md b/README.md index 43d7b71..83dc7fc 100644 --- a/README.md +++ b/README.md @@ -38,13 +38,13 @@ For command-line tools using these respective libraries, see the [Tables and Gra ### 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. Compile with: -* GCC: `g++ -std=c++14 -Wall -g -O3 tables.cpp -o tables` -* Clang: `clang++ -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++17 -Wall -g -O3 tables.cpp -o tables` Other compilers should work as well, but are not (yet) tested. @@ -68,9 +68,7 @@ int main() // Allocate and set array - tables::options aoptions; - aoptions.headerrow = true; - aoptions.headercolumn = true; + tables::options aoptions = {.headerrow = true, .headercolumn = true}; tables::array(rows, columns, array, nullptr, nullptr, aoptions); @@ -99,9 +97,7 @@ int main() string *headerrow = nullptr; string *headercolumn = nullptr; - tables::options aoptions; - aoptions.headerrow = true; - aoptions.headercolumn = true; + tables::options aoptions = {.headerrow = true, .headercolumn = true}; tables::array(array, headerrow, headercolumn, aoptions); @@ -134,9 +130,7 @@ int main() // Allocate and set array - tables::options aoptions; - aoptions.headerrow = true; - aoptions.headercolumn = true; + tables::options aoptions = {.headerrow = true, .headercolumn = true}; tables::array(rows, columns, array, headerrow, headercolumn, aoptions); @@ -165,11 +159,7 @@ int main() // Set array - tables::options aoptions; - aoptions.headerrow = true; - aoptions.headercolumn = true; - // or with C++20: - // tables::options aoptions{.headerrow = true, .headercolumn = true}; + tables::options aoptions = {.headerrow = true, .headercolumn = true}; tables::array(array, headerrow, headercolumn, aoptions); @@ -337,8 +327,7 @@ int main() double xmax = 10; double xstep = 0.5; - tables::options aoptions; - aoptions.headerrow = true; + tables::options aoptions = {.headerrow = true}; tables::function(xmin, xmax, xstep, afunction, aoptions); @@ -362,8 +351,7 @@ int main() function afunction = [](auto x) { return x + 1; }; - tables::options aoptions; - aoptions.headerrow = true; + tables::options aoptions = {.headerrow = true}; 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 functions[] = {function1, function2}; - tables::options aoptions; - aoptions.headerrow = true; + tables::options aoptions = {.headerrow = true}; tables::functions(xmin, xmax, xstep, numfunctions, functions, aoptions); @@ -435,8 +422,7 @@ int main() [](auto x) { return pow(x, 2); }}; - tables::options aoptions; - aoptions.headerrow = true; + tables::options aoptions = {.headerrow = true}; 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 -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. Compile with: -* GCC: `g++ -std=c++14 -Wall -g -O3 graphs.cpp -o graphs` -* Clang: `clang++ -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++17 -Wall -g -O3 graphs.cpp -o graphs` Other compilers should work as well, but are not (yet) tested. diff --git a/graphs.cpp b/graphs.cpp index 7297cc0..7e5d4ca 100644 --- a/graphs.cpp +++ b/graphs.cpp @@ -1,6 +1,6 @@ // 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 @@ -242,7 +242,7 @@ int main() { 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; - 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; aoptions.axisunitslabel = false; - // graphs::options aoptions{.axisunitslabel = false}; + // graphs::options aoptions = {.axisunitslabel = false}; for (const graphs::style_type style : graphs::style_types) { 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; @@ -286,7 +286,7 @@ int main() cout << "\e[1;1H" << "\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); } */ diff --git a/graphs.hpp b/graphs.hpp index 92873fe..f7edcf1 100644 --- a/graphs.hpp +++ b/graphs.hpp @@ -168,52 +168,30 @@ namespace graphs bool check = true; }; - template - constexpr size_t size(const T &array) - { - return distance(cbegin(array), cend(array)); - } - // Number of columns needed to represent the string // 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 (size_t i = 0; i < length; ++i) - if (iscntrl(str[i])) + for (const char c : str) + if (iscntrl(c)) { - cerr << "\nError! Control character in string.\n"; - cout << "Control character: " << (int)str[i] << '\n'; + cerr << "\nError: Control character in string.\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(-1)) - { - cerr << "\nError! mbstowcs failed. Invalid multibyte character.\n"; - exit(1); - } + throw range_error("Error: mbstowcs failed. Invalid multibyte character."); ++length; - auto *wcstring = new wchar_t[length]; - - if (mbstowcs(wcstring, str, length) == static_cast(-1)) - { - if (wcstring) - delete[] wcstring; + wstring wcstring(length, L'\0'); - cerr << "\nError! mbstowcs failed. Invalid multibyte character.\n"; - exit(1); - } + if (mbstowcs(wcstring.data(), str.c_str(), length) == static_cast(-1)) + throw range_error("Error: mbstowcs failed. Invalid multibyte character."); - const int width = wcswidth(wcstring, length); + const int width = wcswidth(wcstring.c_str(), length); if (width == -1) - { - cerr << "\nError! wcswidth failed. Nonprintable wide character.\n"; - exit(1); - } - - if (wcstring) - delete[] wcstring; + throw range_error("Error: wcswidth failed. Nonprintable wide character."); return width; } @@ -221,7 +199,7 @@ namespace graphs // Word wrap // Source: https://gist.github.com/tdulcet/819821ca69501822ad3f84a060c640a0 // 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 wrapped; @@ -245,9 +223,7 @@ namespace graphs ++tempindex; } - const string temp = words.substr(index - linelen, templinelen); - - const size_t width = strcol(temp.c_str()); + const size_t width = strcol(words.substr(index - linelen, templinelen)); if (width >= line_length) { @@ -343,7 +319,8 @@ namespace graphs 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) strm << "i"; @@ -360,7 +337,7 @@ namespace graphs long double intpart = 0; 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) { @@ -377,7 +354,7 @@ namespace graphs 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) { @@ -442,7 +419,7 @@ namespace graphs break; } - const size_t length = strcol(strm.str().c_str()); + const size_t length = strcol(strm.str()); return length; } @@ -450,7 +427,7 @@ namespace graphs // 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> &array, const options &aoptions) { - if (!graphs::size(array)) + if (!size(array)) return 1; const bool border = aoptions.border; @@ -461,10 +438,10 @@ namespace graphs const type_type type = aoptions.type; const char *const title = aoptions.title; - if (height == 0) + if (!height) return 1; - if (width == 0) + if (!width) return 1; struct winsize w; @@ -580,7 +557,7 @@ namespace graphs } else if (axaxis) { - if (i == 0) + if (!i) { cout << astyle[4]; output = true; @@ -611,7 +588,7 @@ namespace graphs } else if (ayaxis) { - if (j == 0) + if (!j) { cout << astyle[2]; output = true; @@ -645,7 +622,7 @@ namespace graphs cout << '0'; 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'; 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'; output = true; @@ -720,7 +697,7 @@ namespace graphs if (type == type_histogram) { if (!dot) - dot = (graphs::size(bars) - l) - 1; + dot = (size(bars) - l) - 1; } else if (type == type_block) dot += blockvalues[k][l]; @@ -776,7 +753,7 @@ namespace graphs template 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; const color_type color = aoptions.color; @@ -784,10 +761,10 @@ namespace graphs struct winsize w; ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); - if (height == 0) + if (!height) height = w.ws_row * 4; - if (width == 0) + if (!width) width = w.ws_col * 2; if (aoptions.check) @@ -811,12 +788,12 @@ namespace graphs height *= 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; - xmax = *minmax.second; + xmin = *amin; + xmax = *amax; } 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; - ymax = *minmax.second; + ymin = *amin; + ymax = *amax; } if (ymin >= ymax) @@ -859,15 +836,16 @@ namespace graphs 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]; for (size_t y = ay >= ymax ? 0 : yaxis - (ay / ystep); y < yaxis and y < height; ++y) aaarray[x][y] = acolor; } - - if (aoptions.type != type_histogram) { + + if (aoptions.type != type_histogram) + { options hist_options = aoptions; hist_options.type = type_histogram; return graph(height, width, xmin, xmax, ymin, ymax, aaarray, hist_options); @@ -878,7 +856,7 @@ namespace graphs template 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; vector aaarray(rows); @@ -891,12 +869,12 @@ namespace graphs template 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; if (!all_of(cbegin(arrays), cend(arrays), [](const auto &array) { 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"; return 1; @@ -907,10 +885,10 @@ namespace graphs struct winsize w; ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); - if (height == 0) + if (!height) height = w.ws_row * 4; - if (width == 0) + if (!width) width = w.ws_col * 2; if (aoptions.check) @@ -934,24 +912,24 @@ namespace graphs if (aoptions.type == type_block) height /= 2; - if (xmin == 0 and xmax == 0) + if (!xmin and !xmax) { const auto compare = [](const auto &a, const auto &b) { return a[0] < b[0]; }; - const auto &result = accumulate(begin(arrays), end(arrays), make_pair(arrays[0][0], arrays[0][0]), [compare](const auto ¤t, 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)); }); - xmin = result.first[0]; - xmax = result.second[0]; + const auto &[amin, amax] = accumulate(cbegin(arrays), cend(arrays), make_pair(arrays[0][0], arrays[0][0]), [&compare](const auto ¤t, const auto &array) + { 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 = amin[0]; + xmax = amax[0]; } - if (ymin == 0 and ymax == 0) + if (!ymin and !ymax) { const auto compare = [](const auto &a, const auto &b) { return a[1] < b[1]; }; - const auto &result = accumulate(begin(arrays), end(arrays), make_pair(arrays[0][0], arrays[0][0]), [compare](const auto ¤t, 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)); }); - ymin = result.first[1]; - ymax = result.second[1]; + const auto &[amin, amax] = accumulate(cbegin(arrays), cend(arrays), make_pair(arrays[0][0], arrays[0][0]), [&compare](const auto ¤t, const auto &array) + { 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 = amin[1]; + ymax = amax[1]; } if (xmin >= xmax) @@ -973,12 +951,12 @@ namespace graphs vector> aarray(width, vector(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 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]; @@ -987,10 +965,10 @@ namespace graphs const size_t ax = (x / xstep) + xaxis; 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 y = ay + mark[1]; + const size_t x = ax + ix; + const size_t y = ay + iy; if (x < width and y < height) { @@ -1023,7 +1001,7 @@ namespace graphs template 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; const size_t columns = 2; @@ -1040,16 +1018,16 @@ namespace graphs { const color_type color = aoptions.color; - if (numfunctions == 0) + if (!numfunctions) return 1; struct winsize w; ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); - if (height == 0) + if (!height) height = w.ws_row * 4; - if (width == 0) + if (!width) width = w.ws_col * 2; if (aoptions.check) @@ -1097,7 +1075,7 @@ namespace graphs 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) { @@ -1140,5 +1118,4 @@ namespace graphs return functions(height, width, xmin, xmax, ymin, ymax, 1, afunctions, aoptions); } - } diff --git a/python/graphs.py b/python/graphs.py index 3d8da8c..64be088 100644 --- a/python/graphs.py +++ b/python/graphs.py @@ -173,10 +173,8 @@ def strcol(astr: str) -> int: """Returns the number of columns that the given string would take up if printed.""" width = wcswidth(astr) if width == -1: - print( - "\nError! wcswidth failed. Nonprintable wide character.", - file=sys.stderr) - sys.exit(1) + msg = "wcswidth failed. Nonprintable wide character." + raise ValueError(msg) return width # return len(astr) @@ -305,10 +303,10 @@ def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax: if not array: return 1 - if height == 0: + if not height: return 1 - if width == 0: + if not width: return 1 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] output = True elif axaxis: - if i == 0: + if not i: strm += astyle[4] output = True elif i >= height - ai: @@ -414,7 +412,7 @@ def graph(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax: strm += astyle[1] output = True elif ayaxis: - if j == 0: + if not j: strm += astyle[2] output = True 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: strm += "0" 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" output = True 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 else: 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" 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: @@ -535,10 +533,10 @@ def histogram(height: int, width: int, xmin: float, xmax: float, ymin: float, ym w = shutil.get_terminal_size() - if height == 0: + if not height: height = w.lines * 4 - if width == 0: + if not width: width = w.columns * 2 if check: @@ -558,7 +556,7 @@ def histogram(height: int, width: int, xmin: float, xmax: float, ymin: float, ym height *= 2 width //= 2 - if xmin == xmax == 0: + if not xmin and not xmax: xmin = min(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) histogram[index] += 1 - if ymin == ymax == 0: + if not ymin and not ymax: ymin = min(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() - if height == 0: + if not height: height = w.lines * 4 - if width == 0: + if not width: width = w.columns * 2 if check: @@ -633,11 +631,11 @@ def plots(height: int, width: int, xmin: float, xmax: float, ymin: float, ymax: if atype == type_types.block: height //= 2 - if xmin == xmax == 0: + if not xmin and not xmax: xmin = min(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) 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() - if height == 0: + if not height: height = w.lines * 4 - if width == 0: + if not width: width = w.columns * 2 if check: diff --git a/python/tables.py b/python/tables.py index fa9617f..ccf55a7 100644 --- a/python/tables.py +++ b/python/tables.py @@ -59,10 +59,8 @@ def strcol(astr: str) -> int: astr = ansi.sub("", astr) width = wcswidth(astr) if width == -1: - print( - "\nError! wcswidth failed. Nonprintable wide character.", - file=sys.stderr) - sys.exit(1) + msg = "wcswidth failed. Nonprintable wide character." + raise ValueError(msg) return width # 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]) 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] else: strm += astyle[0] @@ -118,14 +116,14 @@ def table(array: List[List[str]], headerrow: bool = False, headercolumn: bool = strm += astyle[1] 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] elif j > 0 and (tableborder or (i > 0 and headerrow) or headercolumn): strm += " " 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) 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) @@ -136,29 +134,29 @@ def table(array: List[List[str]], headerrow: bool = False, headercolumn: bool = if i < rows - 1 or tableborder: strm += "\n" - if (i < rows - 1 and cellborder) or (i == 0 and headerrow) or (i < rows - 1 and headercolumn): - if tableborder and (cellborder or (i == 0 and headerrow) or headercolumn): + if (i < rows - 1 and cellborder) or (not i and headerrow) or (i < rows - 1 and headercolumn): + if tableborder and (cellborder or (not i and headerrow) or headercolumn): strm += astyle[5] 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]) elif headercolumn: strm += " " * (2 * padding + columnwidth[j]) 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] - elif i == 0 and headerrow: + elif not i and headerrow: strm += astyle[9] elif headercolumn: - if j == 0: + if not j: strm += astyle[7] else: strm += " " if tableborder: - if cellborder or (i == 0 and headerrow): + if cellborder or (not i and headerrow): strm += astyle[7] elif headercolumn: 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]) if j < columns - 1: - if cellborder or (j == 0 and headercolumn): + if cellborder or (not j and headercolumn): strm += astyle[9] else: strm += astyle[0] diff --git a/python/test.py b/python/test.py index 262e395..5825cf5 100644 --- a/python/test.py +++ b/python/test.py @@ -5,6 +5,7 @@ # Run: python3 -OO test.py import math +import operator import random import sys @@ -87,7 +88,7 @@ def function2(x: float) -> float: array = ([random.randint(0, sys.maxsize) for j in range(columns)] for i in range(rows)) sortdimension = 0 -array = sorted(array, key=lambda x: x[sortdimension]) +array = sorted(array, key=operator.itemgetter(sortdimension)) for style in tables.style_types: tables.array(array, None, None, style=style) diff --git a/tables.cpp b/tables.cpp index c768b6b..8101dec 100644 --- a/tables.cpp +++ b/tables.cpp @@ -1,6 +1,6 @@ // 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 @@ -216,7 +216,7 @@ int main() tables::options aoptions; aoptions.headerrow = 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) { @@ -232,10 +232,7 @@ int main() {"Header column 4", "Data 9", "Data 10", "Data 11", "Data 12"}, {"Header column 5", "Data 13", "Data 14", "Data 15", "Data 16"}}}; - tables::options aoptions; - aoptions.headerrow = 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) { @@ -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 headercolumn[] = {"Header column 2", "Header column 3", "Header column 4", "Header column 5"}; - tables::options aoptions; - aoptions.headerrow = 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) { @@ -295,7 +289,7 @@ int main() aoptions.headercolumn = true; aoptions.cellborder = true; 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); } @@ -304,7 +298,7 @@ int main() aoptions.headerrow = true; aoptions.headercolumn = true; 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); } @@ -315,7 +309,7 @@ int main() tables::options aoptions; aoptions.headerrow = true; aoptions.style = style; - // tables::options aoptions{.headerrow = true, .style = style}; + // tables::options aoptions = {.headerrow = true, .style = style}; tables::array(aarray, headerrow, headercolumn, aoptions); } @@ -326,7 +320,7 @@ int main() tables::options aoptions; aoptions.headercolumn = true; aoptions.style = style; - // tables::options aoptions{.headercolumn = true, .style = style}; + // tables::options aoptions = {.headercolumn = true, .style = style}; tables::array(aarray, headerrow, headercolumn, aoptions); } @@ -337,7 +331,7 @@ int main() tables::options aoptions; aoptions.cellborder = true; aoptions.style = style; - // tables::options aoptions{.cellborder = true, .style = style}; + // tables::options aoptions = {.cellborder = true, .style = style}; tables::array(aarray, headerrow, headercolumn, aoptions); } @@ -348,7 +342,7 @@ int main() tables::options aoptions; aoptions.tableborder = false; aoptions.style = style; - // tables::options aoptions{.tableborder = false, .style = style}; + // tables::options aoptions = {.tableborder = false, .style = style}; tables::array(aarray, headerrow, headercolumn, aoptions); } @@ -358,7 +352,7 @@ int main() aoptions.headerrow = true; aoptions.headercolumn = true; 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); } @@ -370,7 +364,7 @@ int main() aoptions.tableborder = false; aoptions.headerrow = true; 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); } @@ -382,7 +376,7 @@ int main() aoptions.tableborder = false; aoptions.headercolumn = true; 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); } @@ -394,7 +388,7 @@ int main() aoptions.tableborder = false; aoptions.cellborder = true; 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); } @@ -412,7 +406,7 @@ int main() tables::options aoptions; aoptions.boolalpha = true; - // tables::options aoptions{.boolalpha = true}; + // tables::options aoptions = {.boolalpha = true}; for (const tables::style_type style : tables::style_types) { @@ -509,9 +503,7 @@ int main() // Output single function as table cout << "\nOutput single function as table\n\n"; { - tables::options aoptions; - aoptions.headerrow = true; - // tables::options aoptions{.headerrow = true}; + tables::options aoptions = {.headerrow = true}; for (const tables::style_type style : tables::style_types) { @@ -524,9 +516,7 @@ int main() const function afunction = [](auto x) { return x + 1; }; - tables::options aoptions; - aoptions.headerrow = true; - // tables::options aoptions{.headerrow = true}; + tables::options aoptions = {.headerrow = true}; for (const tables::style_type style : tables::style_types) { @@ -540,15 +530,13 @@ int main() { function functions[] = {function1, function2}; - tables::options aoptions; - aoptions.headerrow = true; - // tables::options aoptions{.headerrow = true}; + tables::options aoptions = {.headerrow = true}; for (const tables::style_type style : tables::style_types) { 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) { return pow(x, 2); }}; - tables::options aoptions; - aoptions.headerrow = true; - // tables::options aoptions{.headerrow = true}; + tables::options aoptions = {.headerrow = true}; for (const tables::style_type style : tables::style_types) { aoptions.style = style; - tables::functions(xmin, xmax, xstep, tables::size(functions), functions, aoptions); + tables::functions(xmin, xmax, xstep, size(functions), functions, aoptions); } } diff --git a/tables.hpp b/tables.hpp index 00fd608..71998a2 100644 --- a/tables.hpp +++ b/tables.hpp @@ -65,55 +65,33 @@ namespace tables bool check = true; }; - template - constexpr size_t size(const T &array) - { - return distance(cbegin(array), cend(array)); - } - // Number of columns needed to represent the string // 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, ""); - str = astr.c_str(); + const string str = regex_replace(astr, ansi, ""); - size_t length = strlen(str); - for (size_t i = 0; i < length; ++i) - if (iscntrl(str[i])) + for (const char c : str) + if (iscntrl(c)) { - cerr << "\nError! Control character in string.\n"; - cout << "Control character: " << (int)str[i] << '\n'; + cerr << "\nError: Control character in string.\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(-1)) - { - cerr << "\nError! mbstowcs failed. Invalid multibyte character.\n"; - exit(1); - } + throw range_error("Error: mbstowcs failed. Invalid multibyte character."); ++length; - auto *wcstring = new wchar_t[length]; + wstring wcstring(length, L'\0'); - if (mbstowcs(wcstring, str, length) == static_cast(-1)) - { - if (wcstring) - delete[] wcstring; - - cerr << "\nError! mbstowcs failed. Invalid multibyte character.\n"; - exit(1); - } + if (mbstowcs(wcstring.data(), str.c_str(), length) == static_cast(-1)) + throw range_error("Error: mbstowcs failed. Invalid multibyte character."); - const int width = wcswidth(wcstring, length); + const int width = wcswidth(wcstring.c_str(), length); if (width == -1) - { - cerr << "\nError! wcswidth failed. Nonprintable wide character.\n"; - exit(1); - } + throw range_error("Error: wcswidth failed. Nonprintable wide character."); - if (wcstring) - delete[] wcstring; return width; } @@ -121,7 +99,7 @@ namespace tables // Word wrap // Source: https://gist.github.com/tdulcet/819821ca69501822ad3f84a060c640a0 // 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 wrapped; @@ -145,9 +123,7 @@ namespace tables ++tempindex; } - const string temp = words.substr(index - linelen, templinelen); - - const size_t width = strcol(temp.c_str()); + const size_t width = strcol(words.substr(index - linelen, templinelen)); if (width >= line_length) { @@ -171,7 +147,7 @@ namespace tables template int table(const vector>> &array, const options &aoptions) { - if (!tables::size(array)) + if (!size(array)) return 1; const bool headerrow = aoptions.headerrow; @@ -192,7 +168,7 @@ namespace tables { 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]) columnwidth[j] = cellwidth; } @@ -236,7 +212,7 @@ namespace tables if (j < (columns - 1)) { - if (cellborder or headerrow or (j == 0 and headercolumn)) + if (cellborder or headerrow or (!j and headercolumn)) cout << astyle[3]; else cout << astyle[0]; @@ -253,14 +229,14 @@ namespace tables 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]; else if (j and (tableborder or (i and headerrow) or headercolumn)) 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); @@ -278,17 +254,17 @@ namespace tables if (i < (rows - 1) or tableborder) 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 (cellborder or (i == 0 and headerrow) or headercolumn) + if (cellborder or (!i and headerrow) or headercolumn) cout << astyle[5]; } 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) cout << astyle[0]; else if (headercolumn) @@ -296,13 +272,13 @@ namespace tables 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]; - else if (i == 0 and headerrow) + else if (!i and headerrow) cout << astyle[9]; else if (headercolumn) { - if (j == 0) + if (!j) cout << astyle[7]; else cout << ' '; @@ -312,7 +288,7 @@ namespace tables if (tableborder) { - if (cellborder or (i == 0 and headerrow)) + if (cellborder or (!i and headerrow)) cout << astyle[7]; else if (headercolumn) cout << astyle[1]; @@ -333,7 +309,7 @@ namespace tables if (j < (columns - 1)) { - if (cellborder or (j == 0 and headercolumn)) + if (cellborder or (!j and headercolumn)) cout << astyle[9]; else cout << astyle[0]; @@ -352,17 +328,17 @@ namespace tables template int array(const T1 &aarray, T2 headerrow[] = nullptr, T2 headercolumn[] = nullptr, const options &aoptions = {}) { - if (!tables::size(aarray)) + if (!size(aarray)) return 1; size_t i = 0; size_t j = 0; - size_t rows = tables::size(aarray); - size_t columns = tables::size(aarray[0]); + size_t rows = size(aarray); + size_t columns = size(aarray[0]); 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"; return 1; @@ -460,7 +436,7 @@ namespace tables template int functions(const long double xmin, const long double xmax, const long double xstep, const size_t numfunctions, function functions[], const options &aoptions = {}) { - if (numfunctions == 0) + if (!numfunctions) return 1; if (xmin >= xmax) @@ -481,9 +457,9 @@ namespace tables 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 headerrow(columns); for (size_t j = 0; j < columns; ++j) { @@ -500,7 +476,7 @@ namespace tables } string *headercolumn = nullptr; - // headercolumn = new string[rows + 1]; + // vector headercolumn(rows + 1); // for (size_t i = 0; i < rows + 1; ++i) // { @@ -519,19 +495,7 @@ namespace tables aarray[i][j + 1] = (functions[j])(aarray[i][0]); } - const int code = array(aarray, headerrow, headercolumn, aoptions); - - if (headerrow) - { - delete[] headerrow; - } - - // if (headercolumn) - // { - // delete[] headercolumn; - // } - - return code; + return array(aarray, headerrow.data(), headercolumn, aoptions); } // Convert single function to array and output as table @@ -551,5 +515,4 @@ namespace tables return functions(xmin, xmax, xstep, 1, afunctions, aoptions); } - }