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
- 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

View File

@ -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)

View File

@ -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<double(double)> 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<double(double)> 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.

View File

@ -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);
} */

View File

@ -168,52 +168,30 @@ namespace graphs
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
// 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<size_t>(-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<size_t>(-1))
{
if (wcstring)
delete[] wcstring;
if (mbstowcs(wcstring.data(), str.c_str(), 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);
}
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<vector<unsigned short>> &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 <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 = {})
{
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,7 +836,7 @@ 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];
@ -867,7 +844,8 @@ namespace graphs
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 <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 = {})
{
if (rows == 0)
if (!rows)
return 1;
vector<T> aaarray(rows);
@ -891,12 +869,12 @@ namespace graphs
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 = {})
{
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 &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)); });
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 &current, 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 &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)); });
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 &current, 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<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 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 <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 = {})
{
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);
}
}

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."""
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:

View File

@ -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]

View File

@ -5,6 +5,7 @@
# Run: python3 -OO test.py
import math
import operator
import random
import sys
@ -87,7 +88,7 @@ print("\nOutput sorted array as table\n")
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)

View File

@ -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<long double(long double)> 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<long double(long double)> 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);
}
}

View File

@ -65,55 +65,33 @@ namespace tables
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
// 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<size_t>(-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<size_t>(-1))
{
if (wcstring)
delete[] wcstring;
if (mbstowcs(wcstring.data(), str.c_str(), 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);
}
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 <typename T>
int table(const vector<vector<basic_string<T>>> &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 <typename T1, typename T2>
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 <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 = {})
{
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<string> 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<string> 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);
}
}