diff --git a/README.md b/README.md index d096fe1..4b75d81 100644 --- a/README.md +++ b/README.md @@ -46,11 +46,11 @@ int main() // Allocate and set array - tableoptions aoptions; + tables::options aoptions; aoptions.headerrow = true; aoptions.headercolumn = true; - table(rows, columns, array, nullptr, nullptr, aoptions); + tables::array(rows, columns, array, nullptr, nullptr, aoptions); // Deallocate array @@ -77,11 +77,11 @@ int main() string *headerrow = nullptr; string *headercolumn = nullptr; - tableoptions aoptions; + tables::options aoptions; aoptions.headerrow = true; aoptions.headercolumn = true; - table(array, headerrow, headercolumn, aoptions); + tables::array(array, headerrow, headercolumn, aoptions); return 0; } @@ -112,11 +112,11 @@ int main() // Allocate and set array - tableoptions aoptions; + tables::options aoptions; aoptions.headerrow = true; aoptions.headercolumn = true; - table(rows, columns, array, headerrow, headercolumn, aoptions); + tables::array(rows, columns, array, headerrow, headercolumn, aoptions); // Deallocate array @@ -143,13 +143,13 @@ int main() // Set array - tableoptions aoptions; + tables::options aoptions; aoptions.headerrow = true; aoptions.headercolumn = true; // or with C++20: - // tableoptions aoptions{.headerrow = true, .headercolumn = true}; + // tables::options aoptions{.headerrow = true, .headercolumn = true}; - table(array, headerrow, headercolumn, aoptions); + tables::array(array, headerrow, headercolumn, aoptions); return 0; } @@ -175,7 +175,7 @@ int main() // Allocate and set array - table(rows, columns, array); + tables::array(rows, columns, array); // Deallocate array @@ -199,7 +199,7 @@ int main() // Set array - table(array); + tables::array(array); return 0; } @@ -245,7 +245,7 @@ int main() sort(array, array + rows, compare); - table(rows, columns, array); + tables::array(rows, columns, array); // Deallocate array @@ -287,7 +287,7 @@ int main() sort(array.begin(), array.end(), compare>); - table(array); + tables::array(array); return 0; } @@ -315,10 +315,10 @@ int main() double xmax = 10; double xscl = 2; - tableoptions aoptions; + tables::options aoptions; aoptions.headerrow = true; - table(xmin, xmax, xscl, afunction, aoptions); + tables::function(xmin, xmax, xscl, afunction, aoptions); return 0; } @@ -340,10 +340,10 @@ int main() function afunction = [](auto x) { return x + 1; }; - tableoptions aoptions; + tables::options aoptions; aoptions.headerrow = true; - table(xmin, xmax, xscl, afunction, aoptions); + tables::function(xmin, xmax, xscl, afunction, aoptions); return 0; } @@ -382,10 +382,10 @@ int main() // Function parameter and return value can be any data type, as long as they are the same function functions[] = {function1, function2}; - tableoptions aoptions; + tables::options aoptions; aoptions.headerrow = true; - table(xmin, xmax, xscl, numfunctions, functions, aoptions); + tables::functions(xmin, xmax, xscl, numfunctions, functions, aoptions); return 0; } @@ -413,10 +413,10 @@ int main() [](auto x) { return pow(x, 2); }}; - tableoptions aoptions; + tables::options aoptions; aoptions.headerrow = true; - table(xmin, xmax, xscl, numfunctions, functions, aoptions); + tables::functions(xmin, xmax, xscl, numfunctions, functions, aoptions); return 0; } @@ -549,7 +549,7 @@ int main() // Allocate and set array - graph(height, width, xmin, xmax, ymin, ymax, rows, array); + graphs::array(height, width, xmin, xmax, ymin, ymax, rows, array); // Deallocate array @@ -580,7 +580,7 @@ int main() // Set array - graph(height, width, xmin, xmax, ymin, ymax, array); + graphs::array(height, width, xmin, xmax, ymin, ymax, array); return 0; } @@ -590,7 +590,7 @@ If `xmin` and `xmax` are both `0`, they will be set to the respective minimum an ![](images/array%20to%20plot.png) -Use `graph()` to plot multiple arrays, which can be of different sizes. +Use `graphs::arrays()` to plot multiple arrays, which can be of different sizes. #### Output single function as graph @@ -616,7 +616,7 @@ int main() long double ymin = -20; long double ymax = 20; - graph(height, width, xmin, xmax, ymin, ymax, afunction); + graphs::function(height, width, xmin, xmax, ymin, ymax, afunction); return 0; } @@ -642,7 +642,7 @@ int main() function afunction = [](auto x) { return x + 1; }; - graph(height, width, xmin, xmax, ymin, ymax, afunction); + graphs::function(height, width, xmin, xmax, ymin, ymax, afunction); return 0; } @@ -684,7 +684,7 @@ int main() // Function parameter and return value can be any data type, as long as they are the same function functions[] = {function1, function2}; - graph(height, width, xmin, xmax, ymin, ymax, numfunctions, functions); + graphs::functions(height, width, xmin, xmax, ymin, ymax, numfunctions, functions); return 0; } @@ -715,7 +715,7 @@ int main() [](auto x) { return pow(x, 2); }}; - graph(height, width, xmin, xmax, ymin, ymax, numfunctions, functions); + graphs::functions(height, width, xmin, xmax, ymin, ymax, numfunctions, functions); return 0; } diff --git a/graphs.cpp b/graphs.cpp index 9fc67c4..4d0c74e 100644 --- a/graphs.cpp +++ b/graphs.cpp @@ -66,13 +66,13 @@ int main() for (unsigned int j = 0; j < columns; ++j) array[i][j] = i + j; // rand(); - graphoptions aoptions; + graphs::options aoptions; - for (unsigned int k = 0; k < size(styles); ++k) + for (unsigned int k = 0; k < size(graphs::styles); ++k) { aoptions.style = k; - graph(height, width, xmin, xmax, ymin, ymax, rows, array, aoptions); + graphs::array(height, width, xmin, xmax, ymin, ymax, rows, array, aoptions); } if (array != nullptr) @@ -90,13 +90,13 @@ int main() for (unsigned int j = 0; j < columns; ++j) aarray[i][j] = i + j; // rand(); - graphoptions aoptions; + graphs::options aoptions; - for (unsigned int k = 0; k < size(styles); ++k) + for (unsigned int k = 0; k < size(graphs::styles); ++k) { aoptions.style = k; - graph(height, width, xmin, xmax, ymin, ymax, aarray, aoptions); + graphs::array(height, width, xmin, xmax, ymin, ymax, aarray, aoptions); } } { @@ -106,38 +106,38 @@ int main() for (unsigned int j = 0; j < columns; ++j) array[i][j] = i + j; // rand(); - graphoptions aoptions; + graphs::options aoptions; - for (unsigned int k = 0; k < size(styles); ++k) + for (unsigned int k = 0; k < size(graphs::styles); ++k) { aoptions.style = k; - graph(height, width, xmin, xmax, ymin, ymax, array, aoptions); + graphs::array(height, width, xmin, xmax, ymin, ymax, array, aoptions); } } // Output single function as graph cout << "\nOutput single function as graph\n\n"; { - graphoptions aoptions; + graphs::options aoptions; - for (unsigned int k = 0; k < size(styles); ++k) + for (unsigned int k = 0; k < size(graphs::styles); ++k) { aoptions.style = k; - graph(height, width, xmin, xmax, ymin, ymax, afunction, aoptions); + graphs::function(height, width, xmin, xmax, ymin, ymax, afunction, aoptions); } } { function afunction = [](auto x) { return x + 1; }; - graphoptions aoptions; + graphs::options aoptions; - for (unsigned int k = 0; k < size(styles); ++k) + for (unsigned int k = 0; k < size(graphs::styles); ++k) { aoptions.style = k; - graph(height, width, xmin, xmax, ymin, ymax, afunction, aoptions); + graphs::function(height, width, xmin, xmax, ymin, ymax, afunction, aoptions); } } // Output multiple functions as graph @@ -145,13 +145,13 @@ int main() { function functions[] = {function1, function2}; - graphoptions aoptions; + graphs::options aoptions; - for (unsigned int k = 0; k < size(styles); ++k) + for (unsigned int k = 0; k < size(graphs::styles); ++k) { aoptions.style = k; - graph(height, width, xmin, xmax, ymin, ymax, 2, functions, aoptions); + graphs::functions(height, width, xmin, xmax, ymin, ymax, 2, functions, aoptions); } } { @@ -160,13 +160,13 @@ int main() [](auto x) { return pow(x, 2); }}; - graphoptions aoptions; + graphs::options aoptions; - for (unsigned int k = 0; k < size(styles); ++k) + for (unsigned int k = 0; k < size(graphs::styles); ++k) { aoptions.style = k; - graph(height, width, xmin, xmax, ymin, ymax, 2, functions, aoptions); + graphs::functions(height, width, xmin, xmax, ymin, ymax, 2, functions, aoptions); } } { @@ -177,15 +177,15 @@ int main() function functions[] = {function3, function4, function5}; - graphoptions aoptions; + graphs::options aoptions; aoptions.axisunitslabel = false; - // graphoptions aoptions{.axisunitslabel = false}; + // graphs::options aoptions{.axisunitslabel = false}; - for (unsigned int k = 0; k < size(styles); ++k) + for (unsigned int k = 0; k < size(graphs::styles); ++k) { aoptions.style = k; - graph(height, width, xmin, xmax, ymin, ymax, 3, functions, aoptions); + graphs::functions(height, width, xmin, xmax, ymin, ymax, 3, functions, aoptions); } /* aoptions.style = 2; @@ -195,7 +195,7 @@ int main() cout << "\e[1;1H" << "\e[2J"; - graph(k, k, xmin, xmax, ymin, ymax, 3, functions, aoptions); + graphs::functions(k, k, xmin, xmax, ymin, ymax, 3, functions, aoptions); usleep(200000); } */ diff --git a/graphs.hpp b/graphs.hpp index cb22961..3dc7f92 100644 --- a/graphs.hpp +++ b/graphs.hpp @@ -17,706 +17,710 @@ #include #include -using namespace std; - -const char *const styles[][11] = { - {"-", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"}, // ASCII - {"—", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"}, // Basic - {"─", "│", "┌", "┬", "┐", "├", "┼", "┤", "└", "┴", "┘"}, // Light - {"━", "┃", "┏", "┳", "┓", "┣", "╋", "┫", "┗", "┻", "┛"}, // Heavy - {"═", "║", "╔", "╦", "╗", "╠", "╬", "╣", "╚", "╩", "╝"}, // Double - {"╌", "╎", "┌", "┬", "┐", "├", "┼", "┤", "└", "┴", "┘"}, // Light Dashed - {"╍", "╏", "┏", "┳", "┓", "┣", "╋", "┫", "┗", "┻", "┛"} // Heavy Dashed -}; -// {" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "}};//No border - -const char *const colors[] = {"\e[39m", "\e[30m", "\e[31m", "\e[32m", "\e[33m", "\e[34m", "\e[35m", "\e[36m", "\e[37m", "\e[90m", "\e[91m", "\e[92m", "\e[93m", "\e[94m", "\e[95m", "\e[96m", "\e[97m"}; - -const char *const dots[] = {"⠀", "⠁", "⠂", "⠃", "⠄", "⠅", "⠆", "⠇", "⠈", "⠉", "⠊", "⠋", "⠌", "⠍", "⠎", "⠏", "⠐", "⠑", "⠒", "⠓", "⠔", "⠕", "⠖", "⠗", "⠘", "⠙", "⠚", "⠛", "⠜", "⠝", "⠞", "⠟", "⠠", "⠡", "⠢", "⠣", "⠤", "⠥", "⠦", "⠧", "⠨", "⠩", "⠪", "⠫", "⠬", "⠭", "⠮", "⠯", "⠰", "⠱", "⠲", "⠳", "⠴", "⠵", "⠶", "⠷", "⠸", "⠹", "⠺", "⠻", "⠼", "⠽", "⠾", "⠿", "⡀", "⡁", "⡂", "⡃", "⡄", "⡅", "⡆", "⡇", "⡈", "⡉", "⡊", "⡋", "⡌", "⡍", "⡎", "⡏", "⡐", "⡑", "⡒", "⡓", "⡔", "⡕", "⡖", "⡗", "⡘", "⡙", "⡚", "⡛", "⡜", "⡝", "⡞", "⡟", "⡠", "⡡", "⡢", "⡣", "⡤", "⡥", "⡦", "⡧", "⡨", "⡩", "⡪", "⡫", "⡬", "⡭", "⡮", "⡯", "⡰", "⡱", "⡲", "⡳", "⡴", "⡵", "⡶", "⡷", "⡸", "⡹", "⡺", "⡻", "⡼", "⡽", "⡾", "⡿", "⢀", "⢁", "⢂", "⢃", "⢄", "⢅", "⢆", "⢇", "⢈", "⢉", "⢊", "⢋", "⢌", "⢍", "⢎", "⢏", "⢐", "⢑", "⢒", "⢓", "⢔", "⢕", "⢖", "⢗", "⢘", "⢙", "⢚", "⢛", "⢜", "⢝", "⢞", "⢟", "⢠", "⢡", "⢢", "⢣", "⢤", "⢥", "⢦", "⢧", "⢨", "⢩", "⢪", "⢫", "⢬", "⢭", "⢮", "⢯", "⢰", "⢱", "⢲", "⢳", "⢴", "⢵", "⢶", "⢷", "⢸", "⢹", "⢺", "⢻", "⢼", "⢽", "⢾", "⢿", "⣀", "⣁", "⣂", "⣃", "⣄", "⣅", "⣆", "⣇", "⣈", "⣉", "⣊", "⣋", "⣌", "⣍", "⣎", "⣏", "⣐", "⣑", "⣒", "⣓", "⣔", "⣕", "⣖", "⣗", "⣘", "⣙", "⣚", "⣛", "⣜", "⣝", "⣞", "⣟", "⣠", "⣡", "⣢", "⣣", "⣤", "⣥", "⣦", "⣧", "⣨", "⣩", "⣪", "⣫", "⣬", "⣭", "⣮", "⣯", "⣰", "⣱", "⣲", "⣳", "⣴", "⣵", "⣶", "⣷", "⣸", "⣹", "⣺", "⣻", "⣼", "⣽", "⣾", "⣿"}; - -const int values[][4] = {{0x1, 0x2, 0x4, 0x40}, {0x8, 0x10, 0x20, 0x80}}; - -const char *const fractions[] = {"¼", "½", "¾", "⅐", "⅑", "⅒", "⅓", "⅔", "⅕", "⅖", "⅗", "⅘", "⅙", "⅚", "⅛", "⅜", "⅝", "⅞"}; - -const long double fractionvalues[] = {1.0L / 4.0L, 1.0L / 2.0L, 3.0L / 4.0L, 1.0L / 7.0L, 1.0L / 9.0L, 1.0L / 10.0L, 1.0L / 3.0L, 2.0L / 3.0L, 1.0L / 5.0L, 2.0L / 5.0L, 3.0L / 5.0L, 4.0L / 5.0L, 1.0L / 6.0L, 5.0L / 6.0L, 1.0L / 8.0L, 3.0L / 8.0L, 5.0L / 8.0L, 7.0L / 8.0L}; - -struct graphoptions +namespace graphs { - bool border = true; - bool axislabel = true; - bool axisunitslabel = true; - const char *title = nullptr; - unsigned int style = 2; - unsigned int color = 2; -}; + using namespace std; -const graphoptions defaultoptions; + const char *const styles[][11] = { + {"-", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"}, // ASCII + {"—", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"}, // Basic + {"─", "│", "┌", "┬", "┐", "├", "┼", "┤", "└", "┴", "┘"}, // Light + {"━", "┃", "┏", "┳", "┓", "┣", "╋", "┫", "┗", "┻", "┛"}, // Heavy + {"═", "║", "╔", "╦", "╗", "╠", "╬", "╣", "╚", "╩", "╝"}, // Double + {"╌", "╎", "┌", "┬", "┐", "├", "┼", "┤", "└", "┴", "┘"}, // Light Dashed + {"╍", "╏", "┏", "┳", "┓", "┣", "╋", "┫", "┗", "┻", "┛"} // Heavy Dashed + }; + // {" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "}};//No border -// Number of columns needed to represent the string -// Adapted from: https://stackoverflow.com/a/31124065 -int strcol(const char *const str) -{ - size_t length = strlen(str); - for (size_t i = 0; i < length; ++i) - if (iscntrl(str[i])) + const char *const colors[] = {"\e[39m", "\e[30m", "\e[31m", "\e[32m", "\e[33m", "\e[34m", "\e[35m", "\e[36m", "\e[37m", "\e[90m", "\e[91m", "\e[92m", "\e[93m", "\e[94m", "\e[95m", "\e[96m", "\e[97m"}; + + const char *const dots[] = {"⠀", "⠁", "⠂", "⠃", "⠄", "⠅", "⠆", "⠇", "⠈", "⠉", "⠊", "⠋", "⠌", "⠍", "⠎", "⠏", "⠐", "⠑", "⠒", "⠓", "⠔", "⠕", "⠖", "⠗", "⠘", "⠙", "⠚", "⠛", "⠜", "⠝", "⠞", "⠟", "⠠", "⠡", "⠢", "⠣", "⠤", "⠥", "⠦", "⠧", "⠨", "⠩", "⠪", "⠫", "⠬", "⠭", "⠮", "⠯", "⠰", "⠱", "⠲", "⠳", "⠴", "⠵", "⠶", "⠷", "⠸", "⠹", "⠺", "⠻", "⠼", "⠽", "⠾", "⠿", "⡀", "⡁", "⡂", "⡃", "⡄", "⡅", "⡆", "⡇", "⡈", "⡉", "⡊", "⡋", "⡌", "⡍", "⡎", "⡏", "⡐", "⡑", "⡒", "⡓", "⡔", "⡕", "⡖", "⡗", "⡘", "⡙", "⡚", "⡛", "⡜", "⡝", "⡞", "⡟", "⡠", "⡡", "⡢", "⡣", "⡤", "⡥", "⡦", "⡧", "⡨", "⡩", "⡪", "⡫", "⡬", "⡭", "⡮", "⡯", "⡰", "⡱", "⡲", "⡳", "⡴", "⡵", "⡶", "⡷", "⡸", "⡹", "⡺", "⡻", "⡼", "⡽", "⡾", "⡿", "⢀", "⢁", "⢂", "⢃", "⢄", "⢅", "⢆", "⢇", "⢈", "⢉", "⢊", "⢋", "⢌", "⢍", "⢎", "⢏", "⢐", "⢑", "⢒", "⢓", "⢔", "⢕", "⢖", "⢗", "⢘", "⢙", "⢚", "⢛", "⢜", "⢝", "⢞", "⢟", "⢠", "⢡", "⢢", "⢣", "⢤", "⢥", "⢦", "⢧", "⢨", "⢩", "⢪", "⢫", "⢬", "⢭", "⢮", "⢯", "⢰", "⢱", "⢲", "⢳", "⢴", "⢵", "⢶", "⢷", "⢸", "⢹", "⢺", "⢻", "⢼", "⢽", "⢾", "⢿", "⣀", "⣁", "⣂", "⣃", "⣄", "⣅", "⣆", "⣇", "⣈", "⣉", "⣊", "⣋", "⣌", "⣍", "⣎", "⣏", "⣐", "⣑", "⣒", "⣓", "⣔", "⣕", "⣖", "⣗", "⣘", "⣙", "⣚", "⣛", "⣜", "⣝", "⣞", "⣟", "⣠", "⣡", "⣢", "⣣", "⣤", "⣥", "⣦", "⣧", "⣨", "⣩", "⣪", "⣫", "⣬", "⣭", "⣮", "⣯", "⣰", "⣱", "⣲", "⣳", "⣴", "⣵", "⣶", "⣷", "⣸", "⣹", "⣺", "⣻", "⣼", "⣽", "⣾", "⣿"}; + + const int values[][4] = {{0x1, 0x2, 0x4, 0x40}, {0x8, 0x10, 0x20, 0x80}}; + + const char *const fractions[] = {"¼", "½", "¾", "⅐", "⅑", "⅒", "⅓", "⅔", "⅕", "⅖", "⅗", "⅘", "⅙", "⅚", "⅛", "⅜", "⅝", "⅞"}; + + const long double fractionvalues[] = {1.0L / 4.0L, 1.0L / 2.0L, 3.0L / 4.0L, 1.0L / 7.0L, 1.0L / 9.0L, 1.0L / 10.0L, 1.0L / 3.0L, 2.0L / 3.0L, 1.0L / 5.0L, 2.0L / 5.0L, 3.0L / 5.0L, 4.0L / 5.0L, 1.0L / 6.0L, 5.0L / 6.0L, 1.0L / 8.0L, 3.0L / 8.0L, 5.0L / 8.0L, 7.0L / 8.0L}; + + struct options + { + bool border = true; + bool axislabel = true; + bool axisunitslabel = true; + const char *title = nullptr; + unsigned int style = 2; + unsigned int color = 2; + }; + + const options defaultoptions; + + // Number of columns needed to represent the string + // Adapted from: https://stackoverflow.com/a/31124065 + int strcol(const char *const str) + { + size_t length = strlen(str); + for (size_t i = 0; i < length; ++i) + if (iscntrl(str[i])) + { + cerr << "\nError! Control character in string.\n"; + cout << "Control character: " << (int)str[i] << "\n"; + } + + length = mbstowcs(nullptr, str, 0); + if (length == static_cast(-1)) { - cerr << "\nError! Control character in string.\n"; - cout << "Control character: " << (int)str[i] << "\n"; + cerr << "\nError! mbstowcs failed. Invalid multibyte character.\n"; + exit(1); + } + ++length; + + wchar_t *wcstring = new wchar_t[length]; + + if (mbstowcs(wcstring, str, length) == static_cast(-1)) + { + if (wcstring != nullptr) + delete[] wcstring; + + cerr << "\nError! mbstowcs failed. Invalid multibyte character.\n"; + exit(1); } - length = mbstowcs(nullptr, str, 0); - if (length == static_cast(-1)) - { - cerr << "\nError! mbstowcs failed. Invalid multibyte character.\n"; - exit(1); - } - ++length; + int width = wcswidth(wcstring, length); + if (width == -1) + { + cerr << "\nError! wcswidth failed. Nonprintable wide character.\n"; + exit(1); + } - wchar_t *wcstring = new wchar_t[length]; - - if (mbstowcs(wcstring, str, length) == static_cast(-1)) - { if (wcstring != nullptr) delete[] wcstring; - cerr << "\nError! mbstowcs failed. Invalid multibyte character.\n"; - exit(1); + return width; } - int width = wcswidth(wcstring, length); - if (width == -1) + // Word wrap + // Source: https://gist.github.com/tdulcet/819821ca69501822ad3f84a060c640a0 + // Adapted from: https://stackoverflow.com/a/42016346 and https://stackoverflow.com/a/13094734 + string wrap(const char *const str, const size_t line_length) { - cerr << "\nError! wcswidth failed. Nonprintable wide character.\n"; - exit(1); - } + char words[strlen(str) + 1]; + strcpy(words, str); + string wrapped; - if (wcstring != nullptr) - delete[] wcstring; - - return width; -} - -// Word wrap -// Source: https://gist.github.com/tdulcet/819821ca69501822ad3f84a060c640a0 -// Adapted from: https://stackoverflow.com/a/42016346 and https://stackoverflow.com/a/13094734 -string wrap(const char *const str, const size_t line_length) -{ - char words[strlen(str) + 1]; - strcpy(words, str); - string wrapped; - - size_t index = 0; - size_t linelen = 0; - while (words[index] != '\0') - { - if (words[index] == '\n') + size_t index = 0; + size_t linelen = 0; + while (words[index] != '\0') { - linelen = 0; - } - else if (isspace(words[index])) - { - size_t tempindex = index + 1; - size_t templinelen = linelen; - while (!isspace(words[tempindex]) and words[tempindex] != '\0') + if (words[index] == '\n') { - ++templinelen; - - ++tempindex; - } - - char temp[templinelen + 1]; - strncpy(temp, words + (index - linelen), templinelen); - temp[templinelen] = '\0'; - - size_t width = strcol(temp); - - if (width >= line_length) - { - words[index] = '\n'; linelen = 0; } - } - - if (words[index] == '\t') - linelen += 8 - (linelen % 8); - else if (words[index] != '\n') - ++linelen; - - ++index; - } - wrapped = words; - return wrapped; -} - -// Convert fractions and constants to Unicode characters -size_t outputlabel(const long double label, ostringstream &strm) -{ - bool output = false; - - long double intpart = 0; - long double fractionpart = abs(modf(label, &intpart)); - - for (unsigned int i = 0; i < size(fractions) and !output; ++i) - { - if (abs(fractionpart - fractionvalues[i]) < DBL_EPSILON) - { - if (intpart != 0) - strm << intpart; - - strm << fractions[i]; - - output = true; - } - } - - if (abs(label) >= DBL_EPSILON) - { - if (!output and fmod(label, M_PI) == 0) - { - const char symbol[] = "π"; - - intpart = label / M_PI; - - if (intpart == -1) - strm << "-"; - else if (intpart != 1) - strm << intpart; - - strm << symbol; - - output = true; - } - else if (!output and fmod(label, M_E) == 0) - { - const char symbol[] = "e"; - - intpart = label / M_E; - - if (intpart == -1) - strm << "-"; - else if (intpart != 1) - strm << intpart; - - strm << symbol; - - output = true; - } - } - - if (!output) - strm << label; - - size_t length = strcol(strm.str().c_str()); - - return length; -} - -// Output graph -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 graphoptions &aoptions) -{ - if (!size(array)) - return 1; - - const bool border = aoptions.border; - const bool axislabel = aoptions.axislabel; - const bool axisunitslabel = aoptions.axisunitslabel; - const char *const title = aoptions.title; - const unsigned int style = aoptions.style; - - if (style >= size(styles)) - return 1; - - if (height == 0) - return 1; - - if (width == 0) - return 1; - - struct winsize w; - ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); - - const int aheight = height / 4; - const int awidth = width / 2; - - if (aheight > w.ws_row) - { - cerr << "The height of the graph (" << aheight << ") is greater then the height of the terminal (" << w.ws_row << ").\n"; - return 1; - } - - if (awidth > w.ws_col) - { - cerr << "The width of the graph (" << awidth << ") is greater then the width of the terminal (" << w.ws_col << ").\n"; - return 1; - } - - if (xmin >= xmax) - { - cerr << "xmin must be less than xmax.\n"; - return 1; - } - - if (ymin >= ymax) - { - cerr << "ymin must be less than ymax.\n"; - return 1; - } - - const long double xscl = width / (xmax - xmin); - const long double yscl = height / (ymax - ymin); - const long double xaxis = width - (xmax * xscl); - const long double yaxis = ymax * yscl; - const int divisor = 2 * 4 * ((width / 160.0) > 1 ? (width / 160) + 1 : 1); - - setlocale(LC_CTYPE, ""); - - if (title != nullptr and title[0] != '\0') - cout << wrap(title, w.ws_col) << "\n"; - - for (unsigned int i = 0; i < height; i += 4) - { - const bool ayaxis = (i <= yaxis and (i + 4) > yaxis); - const bool yaxislabel = (i <= (yaxis + 4) and (i + 4) > (yaxis + 4)); - - ostringstream ylabelstrm; - size_t ylabellength = 0; - - if (border and axislabel and axisunitslabel) - { - bool output = false; - long double label = 0; - int adivisor = divisor; - if (i < yaxis) - adivisor = -adivisor; - - for (long double k = yaxis + adivisor; ((i < yaxis and k >= i) or (i > yaxis and k < (i + 4))) and i >= 4 and !output; k += adivisor) + else if (isspace(words[index])) { - if (i <= k and (i + 4) > k) + size_t tempindex = index + 1; + size_t templinelen = linelen; + while (!isspace(words[tempindex]) and words[tempindex] != '\0') { - label = ymax - (k / yscl); + ++templinelen; - output = true; + ++tempindex; + } + + char temp[templinelen + 1]; + strncpy(temp, words + (index - linelen), templinelen); + temp[templinelen] = '\0'; + + size_t width = strcol(temp); + + if (width >= line_length) + { + words[index] = '\n'; + linelen = 0; } } - if (output) + if (words[index] == '\t') + linelen += 8 - (linelen % 8); + else if (words[index] != '\n') + ++linelen; + + ++index; + } + wrapped = words; + return wrapped; + } + + // Convert fractions and constants to Unicode characters + size_t outputlabel(const long double label, ostringstream &strm) + { + bool output = false; + + long double intpart = 0; + long double fractionpart = abs(modf(label, &intpart)); + + for (unsigned int i = 0; i < size(fractions) and !output; ++i) + { + if (abs(fractionpart - fractionvalues[i]) < DBL_EPSILON) { - ylabellength = outputlabel(label, ylabelstrm); - ylabellength *= 2; + if (intpart != 0) + strm << intpart; + + strm << fractions[i]; + + output = true; } } - for (unsigned int j = 0; j < width; j += 2) + if (abs(label) >= DBL_EPSILON) { - const bool axaxis = (j <= xaxis and (j + 2) > xaxis); - const bool xaxislabel = (j <= (xaxis - 2) and (j + 2) > (xaxis - 2)); - - bool output = false; - - if (border) + if (!output and fmod(label, M_PI) == 0) { - if (axaxis and ayaxis) - { - cout << styles[style][6]; - output = true; - } - else if (axaxis) - { - if (axislabel and axisunitslabel) - { - int adivisor = divisor; - if (i < yaxis) - adivisor = -adivisor; + const char symbol[] = "π"; - for (long double k = yaxis + adivisor; ((i < yaxis and k >= i) or (i > yaxis and k < (i + 4))) and i >= 4 and !output; k += adivisor) - { - if (i <= k and (i + 4) > k) - { - cout << styles[style][7]; - output = true; - } - } - } - if (!output) + intpart = label / M_PI; + + if (intpart == -1) + strm << "-"; + else if (intpart != 1) + strm << intpart; + + strm << symbol; + + output = true; + } + else if (!output and fmod(label, M_E) == 0) + { + const char symbol[] = "e"; + + intpart = label / M_E; + + if (intpart == -1) + strm << "-"; + else if (intpart != 1) + strm << intpart; + + strm << symbol; + + output = true; + } + } + + if (!output) + strm << label; + + size_t length = strcol(strm.str().c_str()); + + return length; + } + + // Output graph + 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 (!size(array)) + return 1; + + const bool border = aoptions.border; + const bool axislabel = aoptions.axislabel; + const bool axisunitslabel = aoptions.axisunitslabel; + const char *const title = aoptions.title; + const unsigned int style = aoptions.style; + + if (style >= size(styles)) + return 1; + + if (height == 0) + return 1; + + if (width == 0) + return 1; + + struct winsize w; + ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); + + const int aheight = height / 4; + const int awidth = width / 2; + + if (aheight > w.ws_row) + { + cerr << "The height of the graph (" << aheight << ") is greater then the height of the terminal (" << w.ws_row << ").\n"; + return 1; + } + + if (awidth > w.ws_col) + { + cerr << "The width of the graph (" << awidth << ") is greater then the width of the terminal (" << w.ws_col << ").\n"; + return 1; + } + + if (xmin >= xmax) + { + cerr << "xmin must be less than xmax.\n"; + return 1; + } + + if (ymin >= ymax) + { + cerr << "ymin must be less than ymax.\n"; + return 1; + } + + const long double xscl = width / (xmax - xmin); + const long double yscl = height / (ymax - ymin); + const long double xaxis = width - (xmax * xscl); + const long double yaxis = ymax * yscl; + const int divisor = 2 * 4 * ((width / 160.0) > 1 ? (width / 160) + 1 : 1); + + setlocale(LC_CTYPE, ""); + + if (title != nullptr and title[0] != '\0') + cout << wrap(title, w.ws_col) << "\n"; + + for (unsigned int i = 0; i < height; i += 4) + { + const bool ayaxis = (i <= yaxis and (i + 4) > yaxis); + const bool yaxislabel = (i <= (yaxis + 4) and (i + 4) > (yaxis + 4)); + + ostringstream ylabelstrm; + size_t ylabellength = 0; + + if (border and axislabel and axisunitslabel) + { + bool output = false; + long double label = 0; + int adivisor = divisor; + if (i < yaxis) + adivisor = -adivisor; + + for (long double k = yaxis + adivisor; ((i < yaxis and k >= i) or (i > yaxis and k < (i + 4))) and i >= 4 and !output; k += adivisor) + { + if (i <= k and (i + 4) > k) { - if (i == 0) - cout << styles[style][4]; - else if (i >= (height - 4)) - cout << styles[style][10]; - else - cout << styles[style][1]; + label = ymax - (k / yscl); + output = true; } } - else if (ayaxis) - { - if (axislabel and axisunitslabel) - { - int adivisor = divisor; - if (j < xaxis) - adivisor = -adivisor; - for (long double k = xaxis + adivisor; ((j < xaxis and k >= j) or (j > xaxis and k < (j + 2))) and j < (width - 4) and !output; k += adivisor) - { - if (j <= k and (j + 2) > k) - { - cout << styles[style][3]; - output = true; - } - } - } - if (!output) + if (output) + { + ylabellength = outputlabel(label, ylabelstrm); + ylabellength *= 2; + } + } + + for (unsigned int j = 0; j < width; j += 2) + { + const bool axaxis = (j <= xaxis and (j + 2) > xaxis); + const bool xaxislabel = (j <= (xaxis - 2) and (j + 2) > (xaxis - 2)); + + bool output = false; + + if (border) + { + if (axaxis and ayaxis) { - if (j == 0) - cout << styles[style][2]; - else if (j >= (width - 2)) - cout << styles[style][4]; - else - cout << styles[style][0]; + cout << styles[style][6]; output = true; } - } - else if (yaxislabel and xaxislabel and axislabel and axisunitslabel) - { - cout << "0"; - output = true; - } - else if (j >= (width - 2) and yaxislabel and axislabel) - { - cout << "x"; - output = true; - } - else if (yaxislabel and axislabel and axisunitslabel) - { - long double label = 0; - int adivisor = divisor; - if (j < xaxis) + else if (axaxis) { - adivisor = -adivisor; - j += 2; - } - - for (long double k = xaxis + adivisor; ((j < xaxis and k >= j) or (j > xaxis and k < (j + 2))) and j < (width - 2) and !output; k += adivisor) - { - if (j <= k and (j + 2) > k) + if (axislabel and axisunitslabel) { - label = (k / xscl) + xmin; + int adivisor = divisor; + if (i < yaxis) + adivisor = -adivisor; + for (long double k = yaxis + adivisor; ((i < yaxis and k >= i) or (i > yaxis and k < (i + 4))) and i >= 4 and !output; k += adivisor) + { + if (i <= k and (i + 4) > k) + { + cout << styles[style][7]; + output = true; + } + } + } + if (!output) + { + if (i == 0) + cout << styles[style][4]; + else if (i >= (height - 4)) + cout << styles[style][10]; + else + cout << styles[style][1]; output = true; } } - - if (adivisor < 0) - j -= 2; - - if (output) + else if (ayaxis) { - output = false; - - ostringstream strm; - size_t length = outputlabel(label, strm); - length *= 2; - if ((j >= xaxis or (j + length) < (xaxis - 4)) and (j + length) < (width - 2)) + if (axislabel and axisunitslabel) { - cout << strm.str(); + int adivisor = divisor; + if (j < xaxis) + adivisor = -adivisor; - if (length > 2) - j += length - 2; - - if (adivisor < 0) - output = true; + for (long double k = xaxis + adivisor; ((j < xaxis and k >= j) or (j > xaxis and k < (j + 2))) and j < (width - 4) and !output; k += adivisor) + { + if (j <= k and (j + 2) > k) + { + cout << styles[style][3]; + output = true; + } + } + } + if (!output) + { + if (j == 0) + cout << styles[style][2]; + else if (j >= (width - 2)) + cout << styles[style][4]; else - j += 2; + cout << styles[style][0]; + output = true; } } - } - else if (i == 0 and xaxislabel and axislabel) - { - cout << "y"; - output = true; - } - else if ((j <= (xaxis - ylabellength) and (j + 2) > (xaxis - ylabellength)) and axislabel and axisunitslabel) - { - cout << ylabelstrm.str(); - output = true; - if (ylabellength > 2) - j += ylabellength - 2; - } - } - - if (!output) - { - unsigned int dot = 0; - unsigned short color = 0; - - for (unsigned int k = 0; k < 2 and k < (width - j); ++k) - { - for (unsigned int l = 0; l < 4 and l < (height - i); ++l) + else if (yaxislabel and xaxislabel and axislabel and axisunitslabel) { - dot += (array[j + k][i + l] ? 1 : 0) * values[k][l]; - if (color) + cout << "0"; + output = true; + } + else if (j >= (width - 2) and yaxislabel and axislabel) + { + cout << "x"; + output = true; + } + else if (yaxislabel and axislabel and axisunitslabel) + { + long double label = 0; + int adivisor = divisor; + if (j < xaxis) { - if (array[j + k][i + l] and color != array[j + k][i + l]) - color = 1; + adivisor = -adivisor; + j += 2; } - else - color = array[j + k][i + l]; + + for (long double k = xaxis + adivisor; ((j < xaxis and k >= j) or (j > xaxis and k < (j + 2))) and j < (width - 2) and !output; k += adivisor) + { + if (j <= k and (j + 2) > k) + { + label = (k / xscl) + xmin; + + output = true; + } + } + + if (adivisor < 0) + j -= 2; + + if (output) + { + output = false; + + ostringstream strm; + size_t length = outputlabel(label, strm); + length *= 2; + if ((j >= xaxis or (j + length) < (xaxis - 4)) and (j + length) < (width - 2)) + { + cout << strm.str(); + + if (length > 2) + j += length - 2; + + if (adivisor < 0) + output = true; + else + j += 2; + } + } + } + else if (i == 0 and xaxislabel and axislabel) + { + cout << "y"; + output = true; + } + else if ((j <= (xaxis - ylabellength) and (j + 2) > (xaxis - ylabellength)) and axislabel and axisunitslabel) + { + cout << ylabelstrm.str(); + output = true; + if (ylabellength > 2) + j += ylabellength - 2; } } - if (color) - --color; - - if (color) - cout << colors[color]; - - cout << "\e[1m" << dots[dot] << "\e[22m"; - - if (color) - cout << colors[0]; - } - } - - cout << "\n"; - } - - cout << endl; - - return 0; -} - -// Convert one or more arrays to graph and output -template -int graphs(size_t height, size_t width, long double xmin, long double xmax, long double ymin, long double ymax, const T &arrays, const graphoptions &aoptions = defaultoptions) -{ - if (!size(arrays)) - return 1; - - if (!all_of(begin(arrays), end(arrays), [](const auto &array) - { return all_of(begin(array), end(array), [](const auto &x) - { return size(x) == 2; }); })) - { - cerr << "Error: The arrays must have two columns."; - return 1; - } - - const unsigned int color = aoptions.color; - - if (color >= size(colors)) - return 1; - - struct winsize w; - ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); - - if (height == 0) - height = w.ws_row * 4; - - if (width == 0) - width = w.ws_col * 2; - - const int aheight = height / 4; - const int awidth = width / 2; - - if (aheight > w.ws_row) - { - cerr << "The height of the graph (" << aheight << ") is greater then the height of the terminal (" << w.ws_row << ").\n"; - return 1; - } - - if (awidth > w.ws_col) - { - cerr << "The width of the graph (" << awidth << ") is greater then the width of the terminal (" << w.ws_col << ").\n"; - return 1; - } - - if (xmin == 0 and xmax == 0) - { - 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]; - } - - if (ymin == 0 and ymax == 0) - { - 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]; - } - - if (xmin >= xmax) - { - cerr << "xmin must be less than xmax.\n"; - return 1; - } - - if (ymin >= ymax) - { - cerr << "ymin must be less than ymax.\n"; - return 1; - } - - const long double xscl = width / (xmax - xmin); - const long double yscl = height / (ymax - ymin); - const long double xaxis = width - (xmax * xscl); - const long double yaxis = ymax * yscl; - - vector> aarray(width, vector(height, 0)); - - for (unsigned int j = 0; j < size(arrays); ++j) - { - auto array = arrays[j]; - const unsigned int color = (j % (size(colors) - 2)) + 3; - - for (unsigned int i = 0; i < size(array); ++i) - { - if (array[i][0] >= xmin and array[i][0] < xmax and array[i][1] >= ymin and array[i][1] < ymax) - { - const long long x = (array[i][0] * xscl) + xaxis; - const long long y = (yaxis - (array[i][1] * yscl)) - 1; - - if (aarray[x][y]) + if (!output) { - if (aarray[x][y] != color) - aarray[x][y] = 1; + unsigned int dot = 0; + unsigned short color = 0; + + for (unsigned int k = 0; k < 2 and k < (width - j); ++k) + { + for (unsigned int l = 0; l < 4 and l < (height - i); ++l) + { + dot += (array[j + k][i + l] ? 1 : 0) * values[k][l]; + if (color) + { + if (array[j + k][i + l] and color != array[j + k][i + l]) + color = 1; + } + else + color = array[j + k][i + l]; + } + } + + if (color) + --color; + + if (color) + cout << colors[color]; + + cout << "\e[1m" << dots[dot] << "\e[22m"; + + if (color) + cout << colors[0]; } - else - aarray[x][y] = color; } + + cout << "\n"; } + + cout << endl; + + return 0; } - return graph(height, width, xmin, xmax, ymin, ymax, aarray, aoptions); -} - -// Convert single array to graph and output -template -int graph(size_t height, size_t width, long double xmin, long double xmax, long double ymin, long double ymax, const T &aarray, const graphoptions &aoptions = defaultoptions) -{ - const std::array aaarray = {aarray}; - - return graphs(height, width, xmin, xmax, ymin, ymax, aaarray, aoptions); -} - -// Convert single array to graph and output -template -int graph(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 graphoptions &aoptions = defaultoptions) -{ - if (rows == 0) - return 1; - - const size_t columns = 2; - vector> aaarray(rows); - for (unsigned int i = 0; i < rows; ++i) - copy(aarray[i], aarray[i] + columns, aaarray[i].begin()); - - return graph(height, width, xmin, xmax, ymin, ymax, aaarray, aoptions); -} - -// Convert one or more functions to graph and output -template -int graph(size_t height, size_t width, const long double xmin, const long double xmax, const long double ymin, const long double ymax, const size_t numfunctions, function functions[], const graphoptions &aoptions = defaultoptions) -{ - const unsigned int color = aoptions.color; - - if (color >= size(colors)) - return 1; - - if (numfunctions == 0) - return 1; - - struct winsize w; - ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); - - if (height == 0) - height = w.ws_row * 4; - - if (width == 0) - width = w.ws_col * 2; - - const int aheight = height / 4; - const int awidth = width / 2; - - if (aheight > w.ws_row) + // Convert one or more arrays to graph and output + template + int arrays(size_t height, size_t width, long double xmin, long double xmax, long double ymin, long double ymax, const T &arrays, const options &aoptions = defaultoptions) { - cerr << "The height of the graph (" << aheight << ") is greater then the height of the terminal (" << w.ws_row << ").\n"; - return 1; - } + if (!size(arrays)) + return 1; - if (awidth > w.ws_col) - { - cerr << "The width of the graph (" << awidth << ") is greater then the width of the terminal (" << w.ws_col << ").\n"; - return 1; - } - - if (xmin >= xmax) - { - cerr << "xmin must be less than xmax.\n"; - return 1; - } - - if (ymin >= ymax) - { - cerr << "ymin must be less than ymax.\n"; - return 1; - } - - const size_t rows = width; - - const long double xscl = width / (xmax - xmin); - const long double yscl = height / (ymax - ymin); - const long double xaxis = width - (xmax * xscl); - const long double yaxis = ymax * yscl; - - vector> array(width, vector(height, 0)); - - for (unsigned int j = 0; j < numfunctions; ++j) - { - unsigned short acolor = numfunctions == 1 ? color + 1 : (j % (size(colors) - 2)) + 3; - - for (long double i = 0; i < rows; i += 0.5) + if (!all_of(begin(arrays), end(arrays), [](const auto &array) + { return all_of(begin(array), end(array), [](const auto &x) + { return size(x) == 2; }); })) { - T x = (i / xscl) + xmin; - T y = (functions[j])(x); + cerr << "Error: The arrays must have two columns."; + return 1; + } - if (x >= xmin and x < xmax and y >= ymin and y < ymax) + const unsigned int color = aoptions.color; + + if (color >= size(colors)) + return 1; + + struct winsize w; + ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); + + if (height == 0) + height = w.ws_row * 4; + + if (width == 0) + width = w.ws_col * 2; + + const int aheight = height / 4; + const int awidth = width / 2; + + if (aheight > w.ws_row) + { + cerr << "The height of the graph (" << aheight << ") is greater then the height of the terminal (" << w.ws_row << ").\n"; + return 1; + } + + if (awidth > w.ws_col) + { + cerr << "The width of the graph (" << awidth << ") is greater then the width of the terminal (" << w.ws_col << ").\n"; + return 1; + } + + if (xmin == 0 and xmax == 0) + { + 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]; + } + + if (ymin == 0 and ymax == 0) + { + 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]; + } + + if (xmin >= xmax) + { + cerr << "xmin must be less than xmax.\n"; + return 1; + } + + if (ymin >= ymax) + { + cerr << "ymin must be less than ymax.\n"; + return 1; + } + + const long double xscl = width / (xmax - xmin); + const long double yscl = height / (ymax - ymin); + const long double xaxis = width - (xmax * xscl); + const long double yaxis = ymax * yscl; + + vector> aarray(width, vector(height, 0)); + + for (unsigned int j = 0; j < size(arrays); ++j) + { + auto array = arrays[j]; + const unsigned int color = (j % (size(colors) - 2)) + 3; + + for (unsigned int i = 0; i < size(array); ++i) { - const long long ax = (x * xscl) + xaxis; - const long long ay = (yaxis - (y * yscl)) - 1; - - if (array[ax][ay]) + if (array[i][0] >= xmin and array[i][0] < xmax and array[i][1] >= ymin and array[i][1] < ymax) { - if (array[ax][ay] != acolor) - array[ax][ay] = 1; + const long long x = (array[i][0] * xscl) + xaxis; + const long long y = (yaxis - (array[i][1] * yscl)) - 1; + + if (aarray[x][y]) + { + if (aarray[x][y] != color) + aarray[x][y] = 1; + } + else + aarray[x][y] = color; } - else - array[ax][ay] = acolor; } } + + return graph(height, width, xmin, xmax, ymin, ymax, aarray, aoptions); + } + + // Convert single array to graph and output + template + int array(size_t height, size_t width, long double xmin, long double xmax, long double ymin, long double ymax, const T &aarray, const options &aoptions = defaultoptions) + { + const std::array aaarray = {aarray}; + + return arrays(height, width, xmin, xmax, ymin, ymax, aaarray, aoptions); + } + + // Convert single array to graph and output + template + int array(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 = defaultoptions) + { + if (rows == 0) + return 1; + + const size_t columns = 2; + vector> aaarray(rows); + for (unsigned int i = 0; i < rows; ++i) + copy(aarray[i], aarray[i] + columns, aaarray[i].begin()); + + return array(height, width, xmin, xmax, ymin, ymax, aaarray, aoptions); + } + + // Convert one or more functions to graph and output + template + int functions(size_t height, size_t width, const long double xmin, const long double xmax, const long double ymin, const long double ymax, const size_t numfunctions, function functions[], const options &aoptions = defaultoptions) + { + const unsigned int color = aoptions.color; + + if (color >= size(colors)) + return 1; + + if (numfunctions == 0) + return 1; + + struct winsize w; + ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); + + if (height == 0) + height = w.ws_row * 4; + + if (width == 0) + width = w.ws_col * 2; + + const int aheight = height / 4; + const int awidth = width / 2; + + if (aheight > w.ws_row) + { + cerr << "The height of the graph (" << aheight << ") is greater then the height of the terminal (" << w.ws_row << ").\n"; + return 1; + } + + if (awidth > w.ws_col) + { + cerr << "The width of the graph (" << awidth << ") is greater then the width of the terminal (" << w.ws_col << ").\n"; + return 1; + } + + if (xmin >= xmax) + { + cerr << "xmin must be less than xmax.\n"; + return 1; + } + + if (ymin >= ymax) + { + cerr << "ymin must be less than ymax.\n"; + return 1; + } + + const size_t rows = width; + + const long double xscl = width / (xmax - xmin); + const long double yscl = height / (ymax - ymin); + const long double xaxis = width - (xmax * xscl); + const long double yaxis = ymax * yscl; + + vector> array(width, vector(height, 0)); + + for (unsigned int j = 0; j < numfunctions; ++j) + { + unsigned short acolor = numfunctions == 1 ? color + 1 : (j % (size(colors) - 2)) + 3; + + for (long double i = 0; i < rows; i += 0.5) + { + T x = (i / xscl) + xmin; + T y = (functions[j])(x); + + if (x >= xmin and x < xmax and y >= ymin and y < ymax) + { + const long long ax = (x * xscl) + xaxis; + const long long ay = (yaxis - (y * yscl)) - 1; + + if (array[ax][ay]) + { + if (array[ax][ay] != acolor) + array[ax][ay] = 1; + } + else + array[ax][ay] = acolor; + } + } + } + + return graph(height, width, xmin, xmax, ymin, ymax, array, aoptions); + } + + // Convert single function to function array and output + template + int function(size_t height, size_t width, const long double xmin, const long double xmax, const long double ymin, const long double ymax, const function &afunction, const options &aoptions = defaultoptions) + { + std::function afunctions[] = {afunction}; + + return functions(height, width, xmin, xmax, ymin, ymax, 1, afunctions, aoptions); + } + + // Convert single function to function array and output + template + int function(size_t height, size_t width, const long double xmin, const long double xmax, const long double ymin, const long double ymax, T afunction(T), const options &aoptions = defaultoptions) + { + std::function afunctions[] = {afunction}; + + return functions(height, width, xmin, xmax, ymin, ymax, 1, afunctions, aoptions); } - return graph(height, width, xmin, xmax, ymin, ymax, array, aoptions); -} - -// Convert single function to function array and output -template -int graph(size_t height, size_t width, const long double xmin, const long double xmax, const long double ymin, const long double ymax, const function &afunction, const graphoptions &aoptions = defaultoptions) -{ - std::function afunctions[] = {afunction}; - - return graph(height, width, xmin, xmax, ymin, ymax, 1, afunctions, aoptions); -} - -// Convert single function to function array and output -template -int graph(size_t height, size_t width, const long double xmin, const long double xmax, const long double ymin, const long double ymax, T afunction(T), const graphoptions &aoptions = defaultoptions) -{ - std::function afunctions[] = {afunction}; - - return graph(height, width, xmin, xmax, ymin, ymax, 1, afunctions, aoptions); } diff --git a/tables.cpp b/tables.cpp index fcebae8..d1a2467 100644 --- a/tables.cpp +++ b/tables.cpp @@ -94,13 +94,13 @@ int main() for (unsigned int j = 0; j < columns; ++j) array[i][j] = rand(); - tableoptions aoptions; + tables::options aoptions; - for (unsigned int k = 0; k < size(styles); ++k) + for (unsigned int k = 0; k < size(tables::styles); ++k) { aoptions.style = k; - table(rows, columns, array, nullptr, nullptr, aoptions); + tables::array(rows, columns, array, nullptr, nullptr, aoptions); } if (array != nullptr) @@ -118,13 +118,13 @@ int main() for (unsigned int j = 0; j < columns; ++j) aarray[i][j] = rand(); - tableoptions aoptions; + tables::options aoptions; - for (unsigned int k = 0; k < size(styles); ++k) + for (unsigned int k = 0; k < size(tables::styles); ++k) { aoptions.style = k; - table(aarray, headerrow, headercolumn, aoptions); + tables::array(aarray, headerrow, headercolumn, aoptions); } } { @@ -134,13 +134,13 @@ int main() for (unsigned int j = 0; j < columns; ++j) array[i][j] = rand(); - tableoptions aoptions; + tables::options aoptions; - for (unsigned int k = 0; k < size(styles); ++k) + for (unsigned int k = 0; k < size(tables::styles); ++k) { aoptions.style = k; - table(array, headerrow, headercolumn, aoptions); + tables::array(array, headerrow, headercolumn, aoptions); } } { @@ -153,13 +153,13 @@ int main() for (unsigned int j = 0; j < columns; ++j) array[i][j] = static_cast(rand()) / static_cast(RAND_MAX); - tableoptions aoptions; + tables::options aoptions; - for (unsigned int k = 0; k < size(styles); ++k) + for (unsigned int k = 0; k < size(tables::styles); ++k) { aoptions.style = k; - table(rows, columns, array, nullptr, nullptr, aoptions); + tables::array(rows, columns, array, nullptr, nullptr, aoptions); } if (array != nullptr) @@ -177,13 +177,13 @@ int main() for (unsigned int j = 0; j < columns; ++j) aarray[i][j] = static_cast(rand()) / static_cast(RAND_MAX); - tableoptions aoptions; + tables::options aoptions; - for (unsigned int k = 0; k < size(styles); ++k) + for (unsigned int k = 0; k < size(tables::styles); ++k) { aoptions.style = k; - table(aarray, headerrow, headercolumn, aoptions); + tables::array(aarray, headerrow, headercolumn, aoptions); } } { @@ -193,13 +193,13 @@ int main() for (unsigned int j = 0; j < columns; ++j) array[i][j] = static_cast(rand()) / static_cast(RAND_MAX); - tableoptions aoptions; + tables::options aoptions; - for (unsigned int k = 0; k < size(styles); ++k) + for (unsigned int k = 0; k < size(tables::styles); ++k) { aoptions.style = k; - table(array, headerrow, headercolumn, aoptions); + tables::array(array, headerrow, headercolumn, aoptions); } } // Output char array as table @@ -212,16 +212,16 @@ int main() {"Header column 4", "Data 9", "Data 10", "Data 11", "Data 12"}, {"Header column 5", "Data 13", "Data 14", "Data 15", "Data 16"}}; - tableoptions aoptions; + tables::options aoptions; aoptions.headerrow = true; aoptions.headercolumn = true; - // tableoptions aoptions{.headerrow = true, .headercolumn = true}; + // tables::options aoptions{.headerrow = true, .headercolumn = true}; - for (unsigned int k = 0; k < size(styles); ++k) + for (unsigned int k = 0; k < size(tables::styles); ++k) { aoptions.style = k; - table(array, headerrow, headercolumn, aoptions); + tables::array(array, headerrow, headercolumn, aoptions); } } { @@ -231,16 +231,16 @@ int main() {"Header column 4", "Data 9", "Data 10", "Data 11", "Data 12"}, {"Header column 5", "Data 13", "Data 14", "Data 15", "Data 16"}}}; - tableoptions aoptions; + tables::options aoptions; aoptions.headerrow = true; aoptions.headercolumn = true; - // tableoptions aoptions{.headerrow = true, .headercolumn = true}; + // tables::options aoptions{.headerrow = true, .headercolumn = true}; - for (unsigned int k = 0; k < size(styles); ++k) + for (unsigned int k = 0; k < size(tables::styles); ++k) { aoptions.style = k; - table(aarray, headerrow, headercolumn, aoptions); + tables::array(aarray, headerrow, headercolumn, aoptions); } } // Output array as table with separate header row and column @@ -258,16 +258,16 @@ 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"}; - tableoptions aoptions; + tables::options aoptions; aoptions.headerrow = true; aoptions.headercolumn = true; - // tableoptions aoptions{.headerrow = true, .headercolumn = true}; + // tables::options aoptions{.headerrow = true, .headercolumn = true}; - for (unsigned int k = 0; k < size(styles); ++k) + for (unsigned int k = 0; k < size(tables::styles); ++k) { aoptions.style = k; - table(array, headerrow, headercolumn, aoptions); + tables::array(array, headerrow, headercolumn, aoptions); } } { @@ -286,116 +286,116 @@ int main() vector aheadercolumn(headerrow, headerrow + 1); aheadercolumn.insert(aheadercolumn.end(), headercolumn, headercolumn + columns - 1); - for (unsigned int k = 0; k < size(styles); ++k) + for (unsigned int k = 0; k < size(tables::styles); ++k) { { - tableoptions aoptions; + tables::options aoptions; aoptions.headerrow = true; aoptions.headercolumn = true; aoptions.cellborder = true; aoptions.style = k; - // tableoptions aoptions{.headerrow = true, .headercolumn = true, .cellborder = true, .style = k}; + // tables::options aoptions{.headerrow = true, .headercolumn = true, .cellborder = true, .style = k}; - table(aarray, headerrow, headercolumn, aoptions); + tables::array(aarray, headerrow, headercolumn, aoptions); } { - tableoptions aoptions; + tables::options aoptions; aoptions.headerrow = true; aoptions.headercolumn = true; aoptions.style = k; - // tableoptions aoptions{.headerrow = true, .headercolumn = true, .style = k}; + // tables::options aoptions{.headerrow = true, .headercolumn = true, .style = k}; - table(aarray, headerrow, headercolumn, aoptions); + tables::array(aarray, headerrow, headercolumn, aoptions); } { string *headerrow = aheaderrow.data(); string *headercolumn = nullptr; - tableoptions aoptions; + tables::options aoptions; aoptions.headerrow = true; aoptions.style = k; - // tableoptions aoptions{.headerrow = true, .style = k}; + // tables::options aoptions{.headerrow = true, .style = k}; - table(aarray, headerrow, headercolumn, aoptions); + tables::array(aarray, headerrow, headercolumn, aoptions); } { string *headerrow = nullptr; string *headercolumn = aheadercolumn.data(); - tableoptions aoptions; + tables::options aoptions; aoptions.headercolumn = true; aoptions.style = k; - // tableoptions aoptions{.headercolumn = true, .style = k}; + // tables::options aoptions{.headercolumn = true, .style = k}; - table(aarray, headerrow, headercolumn, aoptions); + tables::array(aarray, headerrow, headercolumn, aoptions); } { string *headerrow = nullptr; string *headercolumn = nullptr; - tableoptions aoptions; + tables::options aoptions; aoptions.cellborder = true; aoptions.style = k; - // tableoptions aoptions{.cellborder = true, .style = k}; + // tables::options aoptions{.cellborder = true, .style = k}; - table(aarray, headerrow, headercolumn, aoptions); + tables::array(aarray, headerrow, headercolumn, aoptions); } { string *headerrow = nullptr; string *headercolumn = nullptr; - tableoptions aoptions; + tables::options aoptions; aoptions.tableborder = false; aoptions.style = k; - // tableoptions aoptions{.tableborder = false, .style = k}; + // tables::options aoptions{.tableborder = false, .style = k}; - table(aarray, headerrow, headercolumn, aoptions); + tables::array(aarray, headerrow, headercolumn, aoptions); } { - tableoptions aoptions; + tables::options aoptions; aoptions.tableborder = false; aoptions.headerrow = true; aoptions.headercolumn = true; aoptions.style = k; - // tableoptions aoptions{.tableborder = false, .headerrow = true, .headercolumn = true, .style = k}; + // tables::options aoptions{.tableborder = false, .headerrow = true, .headercolumn = true, .style = k}; - table(aarray, headerrow, headercolumn, aoptions); + tables::array(aarray, headerrow, headercolumn, aoptions); } { string *headerrow = aheaderrow.data(); string *headercolumn = nullptr; - tableoptions aoptions; + tables::options aoptions; aoptions.tableborder = false; aoptions.headerrow = true; aoptions.style = k; - // tableoptions aoptions{.tableborder = false, .headerrow = true, .style = k}; + // tables::options aoptions{.tableborder = false, .headerrow = true, .style = k}; - table(aarray, headerrow, headercolumn, aoptions); + tables::array(aarray, headerrow, headercolumn, aoptions); } { string *headerrow = nullptr; string *headercolumn = aheadercolumn.data(); - tableoptions aoptions; + tables::options aoptions; aoptions.tableborder = false; aoptions.headercolumn = true; aoptions.style = k; - // tableoptions aoptions{.tableborder = false, .headercolumn = true, .style = k}; + // tables::options aoptions{.tableborder = false, .headercolumn = true, .style = k}; - table(aarray, headerrow, headercolumn, aoptions); + tables::array(aarray, headerrow, headercolumn, aoptions); } { string *headerrow = nullptr; string *headercolumn = nullptr; - tableoptions aoptions; + tables::options aoptions; aoptions.tableborder = false; aoptions.cellborder = true; aoptions.style = k; - // tableoptions aoptions{.tableborder = false, .cellborder = true, .style = k}; + // tables::options aoptions{.tableborder = false, .cellborder = true, .style = k}; - table(aarray, headerrow, headercolumn, aoptions); + tables::array(aarray, headerrow, headercolumn, aoptions); } } } @@ -409,15 +409,15 @@ int main() for (unsigned int j = 0; j < columns; ++j) array[i][j] = rand() % 2; - tableoptions aoptions; + tables::options aoptions; aoptions.boolalpha = true; - // tableoptions aoptions{.boolalpha = true}; + // tables::options aoptions{.boolalpha = true}; - for (unsigned int k = 0; k < size(styles); ++k) + for (unsigned int k = 0; k < size(tables::styles); ++k) { aoptions.style = k; - table(rows, columns, array, nullptr, nullptr, aoptions); + tables::array(rows, columns, array, nullptr, nullptr, aoptions); } if (array != nullptr) @@ -446,13 +446,13 @@ int main() // qsort(array, rows, sizeof(array[0]), compare); sort(array, array + rows, compare); - tableoptions aoptions; + tables::options aoptions; - for (unsigned int k = 0; k < size(styles); ++k) + for (unsigned int k = 0; k < size(tables::styles); ++k) { aoptions.style = k; - table(rows, columns, array, nullptr, nullptr, aoptions); + tables::array(rows, columns, array, nullptr, nullptr, aoptions); } if (array != nullptr) @@ -475,13 +475,13 @@ int main() sort(aarray.begin(), aarray.end(), compare>); - tableoptions aoptions; + tables::options aoptions; - for (unsigned int k = 0; k < size(styles); ++k) + for (unsigned int k = 0; k < size(tables::styles); ++k) { aoptions.style = k; - table(aarray, headerrow, headercolumn, aoptions); + tables::array(aarray, headerrow, headercolumn, aoptions); } } { @@ -496,42 +496,42 @@ int main() sort(array.begin(), array.end(), compare>); - tableoptions aoptions; + tables::options aoptions; - for (unsigned int k = 0; k < size(styles); ++k) + for (unsigned int k = 0; k < size(tables::styles); ++k) { aoptions.style = k; - table(array, headerrow, headercolumn, aoptions); + tables::array(array, headerrow, headercolumn, aoptions); } } // Output single function as table cout << "\nOutput single function as table\n\n"; { - tableoptions aoptions; + tables::options aoptions; aoptions.headerrow = true; - // tableoptions aoptions{.headerrow = true}; + // tables::options aoptions{.headerrow = true}; - for (unsigned int k = 0; k < size(styles); ++k) + for (unsigned int k = 0; k < size(tables::styles); ++k) { aoptions.style = k; - table(xmin, xmax, xscl, afunction, aoptions); + tables::function(xmin, xmax, xscl, afunction, aoptions); } } { function afunction = [](auto x) { return x + 1; }; - tableoptions aoptions; + tables::options aoptions; aoptions.headerrow = true; - // tableoptions aoptions{.headerrow = true}; + // tables::options aoptions{.headerrow = true}; - for (unsigned int k = 0; k < size(styles); ++k) + for (unsigned int k = 0; k < size(tables::styles); ++k) { aoptions.style = k; - table(xmin, xmax, xscl, afunction, aoptions); + tables::function(xmin, xmax, xscl, afunction, aoptions); } } // Output multiple functions as table @@ -539,15 +539,15 @@ int main() { function functions[] = {function1, function2}; - tableoptions aoptions; + tables::options aoptions; aoptions.headerrow = true; - // tableoptions aoptions{.headerrow = true}; + // tables::options aoptions{.headerrow = true}; - for (unsigned int k = 0; k < size(styles); ++k) + for (unsigned int k = 0; k < size(tables::styles); ++k) { aoptions.style = k; - table(xmin, xmax, xscl, 2, functions, aoptions); + tables::functions(xmin, xmax, xscl, 2, functions, aoptions); } } { @@ -556,15 +556,15 @@ int main() [](auto x) { return pow(x, 2); }}; - tableoptions aoptions; + tables::options aoptions; aoptions.headerrow = true; - // tableoptions aoptions{.headerrow = true}; + // tables::options aoptions{.headerrow = true}; - for (unsigned int k = 0; k < size(styles); ++k) + for (unsigned int k = 0; k < size(tables::styles); ++k) { aoptions.style = k; - table(xmin, xmax, xscl, 2, functions, aoptions); + tables::functions(xmin, xmax, xscl, 2, functions, aoptions); } } diff --git a/tables.hpp b/tables.hpp index b064026..53b488c 100644 --- a/tables.hpp +++ b/tables.hpp @@ -13,509 +13,513 @@ #include #include -using namespace std; - -const char *const styles[][11] = { - {"-", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"}, // ASCII - {"—", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"}, // Basic - {"─", "│", "┌", "┬", "┐", "├", "┼", "┤", "└", "┴", "┘"}, // Light - {"━", "┃", "┏", "┳", "┓", "┣", "╋", "┫", "┗", "┻", "┛"}, // Heavy - {"═", "║", "╔", "╦", "╗", "╠", "╬", "╣", "╚", "╩", "╝"}, // Double - {"╌", "╎", "┌", "┬", "┐", "├", "┼", "┤", "└", "┴", "┘"}, // Light Dashed - {"╍", "╏", "┏", "┳", "┓", "┣", "╋", "┫", "┗", "┻", "┛"} // Heavy Dashed -}; -// {" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "}};//No border - -regex ansi(R"(\x1B\[(?:[0-9]+(?:;[0-9]+)*)?m)"); - -struct tableoptions +namespace tables { - bool headerrow = false; - bool headercolumn = false; - bool tableborder = true; - bool cellborder = false; - unsigned int padding = 1; - ios_base &(*alignment)(ios_base &) = left; - bool boolalpha = false; - const char *title = nullptr; - unsigned int style = 2; -}; + using namespace std; -const tableoptions defaultoptions; + const char *const styles[][11] = { + {"-", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"}, // ASCII + {"—", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"}, // Basic + {"─", "│", "┌", "┬", "┐", "├", "┼", "┤", "└", "┴", "┘"}, // Light + {"━", "┃", "┏", "┳", "┓", "┣", "╋", "┫", "┗", "┻", "┛"}, // Heavy + {"═", "║", "╔", "╦", "╗", "╠", "╬", "╣", "╚", "╩", "╝"}, // Double + {"╌", "╎", "┌", "┬", "┐", "├", "┼", "┤", "└", "┴", "┘"}, // Light Dashed + {"╍", "╏", "┏", "┳", "┓", "┣", "╋", "┫", "┗", "┻", "┛"} // Heavy Dashed + }; + // {" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "}};//No border -// Number of columns needed to represent the string -// Adapted from: https://stackoverflow.com/a/31124065 -int strcol(const char *str) -{ - const string astr = regex_replace(str, ansi, ""); - str = astr.c_str(); + regex ansi(R"(\x1B\[(?:[0-9]+(?:;[0-9]+)*)?m)"); - size_t length = strlen(str); - for (size_t i = 0; i < length; ++i) - if (iscntrl(str[i])) + struct options + { + bool headerrow = false; + bool headercolumn = false; + bool tableborder = true; + bool cellborder = false; + unsigned int padding = 1; + ios_base &(*alignment)(ios_base &) = left; + bool boolalpha = false; + const char *title = nullptr; + unsigned int style = 2; + }; + + const options defaultoptions; + + // Number of columns needed to represent the string + // Adapted from: https://stackoverflow.com/a/31124065 + int strcol(const char *str) + { + const string astr = regex_replace(str, ansi, ""); + str = astr.c_str(); + + size_t length = strlen(str); + for (size_t i = 0; i < length; ++i) + if (iscntrl(str[i])) + { + cerr << "\nError! Control character in string.\n"; + cout << "Control character: " << (int)str[i] << "\n"; + } + + length = mbstowcs(nullptr, str, 0); + if (length == static_cast(-1)) { - cerr << "\nError! Control character in string.\n"; - cout << "Control character: " << (int)str[i] << "\n"; + cerr << "\nError! mbstowcs failed. Invalid multibyte character.\n"; + exit(1); + } + ++length; + + wchar_t *wcstring = new wchar_t[length]; + + if (mbstowcs(wcstring, str, length) == static_cast(-1)) + { + if (wcstring != nullptr) + delete[] wcstring; + + cerr << "\nError! mbstowcs failed. Invalid multibyte character.\n"; + exit(1); } - length = mbstowcs(nullptr, str, 0); - if (length == static_cast(-1)) - { - cerr << "\nError! mbstowcs failed. Invalid multibyte character.\n"; - exit(1); - } - ++length; + int width = wcswidth(wcstring, length); + if (width == -1) + { + cerr << "\nError! wcswidth failed. Nonprintable wide character.\n"; + exit(1); + } - wchar_t *wcstring = new wchar_t[length]; - - if (mbstowcs(wcstring, str, length) == static_cast(-1)) - { if (wcstring != nullptr) delete[] wcstring; - cerr << "\nError! mbstowcs failed. Invalid multibyte character.\n"; - exit(1); + return width; } - int width = wcswidth(wcstring, length); - if (width == -1) + // Word wrap + // Source: https://gist.github.com/tdulcet/819821ca69501822ad3f84a060c640a0 + // Adapted from: https://stackoverflow.com/a/42016346 and https://stackoverflow.com/a/13094734 + string wrap(const char *const str, const size_t line_length) { - cerr << "\nError! wcswidth failed. Nonprintable wide character.\n"; - exit(1); - } + char words[strlen(str) + 1]; + strcpy(words, str); + string wrapped; - if (wcstring != nullptr) - delete[] wcstring; - - return width; -} - -// Word wrap -// Source: https://gist.github.com/tdulcet/819821ca69501822ad3f84a060c640a0 -// Adapted from: https://stackoverflow.com/a/42016346 and https://stackoverflow.com/a/13094734 -string wrap(const char *const str, const size_t line_length) -{ - char words[strlen(str) + 1]; - strcpy(words, str); - string wrapped; - - size_t index = 0; - size_t linelen = 0; - while (words[index] != '\0') - { - if (words[index] == '\n') + size_t index = 0; + size_t linelen = 0; + while (words[index] != '\0') { - linelen = 0; - } - else if (isspace(words[index])) - { - size_t tempindex = index + 1; - size_t templinelen = linelen; - while (!isspace(words[tempindex]) and words[tempindex] != '\0') + if (words[index] == '\n') { - ++templinelen; - - ++tempindex; - } - - char temp[templinelen + 1]; - strncpy(temp, words + (index - linelen), templinelen); - temp[templinelen] = '\0'; - - size_t width = strcol(temp); - - if (width >= line_length) - { - words[index] = '\n'; linelen = 0; } + else if (isspace(words[index])) + { + size_t tempindex = index + 1; + size_t templinelen = linelen; + while (!isspace(words[tempindex]) and words[tempindex] != '\0') + { + ++templinelen; + + ++tempindex; + } + + char temp[templinelen + 1]; + strncpy(temp, words + (index - linelen), templinelen); + temp[templinelen] = '\0'; + + size_t width = strcol(temp); + + if (width >= line_length) + { + words[index] = '\n'; + linelen = 0; + } + } + + if (words[index] == '\t') + linelen += 8 - (linelen % 8); + else if (words[index] != '\n') + ++linelen; + + ++index; + } + wrapped = words; + return wrapped; + } + + // Output char array as table + template + int table(const vector>> &array, const options &aoptions) + { + if (!size(array)) + return 1; + + const bool headerrow = aoptions.headerrow; + const bool headercolumn = aoptions.headercolumn; + const bool tableborder = aoptions.tableborder; + const bool cellborder = aoptions.cellborder; + const unsigned int padding = aoptions.padding; + const char *const title = aoptions.title; + const unsigned int style = aoptions.style; + + if (style >= size(styles)) + return 1; + + const size_t rows = array.size(); + const size_t columns = array[0].size(); + + int columnwidth[columns]; + for (unsigned int j = 0; j < columns; ++j) + columnwidth[j] = 0; + + int width = 0; + + setlocale(LC_CTYPE, ""); + + for (unsigned int j = 0; j < columns; ++j) + { + for (unsigned int i = 0; i < rows; ++i) + { + int cellwidth = strcol(array[i][j].c_str()); + if (cellwidth > columnwidth[j]) + columnwidth[j] = cellwidth; + } + + width += columnwidth[j]; } - if (words[index] == '\t') - linelen += 8 - (linelen % 8); - else if (words[index] != '\n') - ++linelen; + struct winsize w; + ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); - ++index; - } - wrapped = words; - return wrapped; -} + if (tableborder or cellborder or headerrow or headercolumn) + width += (((2 * padding) + 1) * columns) + (tableborder ? 1 : -1); + else + width += (2 * padding) * columns; -// Output char array as table -template -int table(const vector>> &array, const tableoptions &aoptions) -{ - if (!size(array)) - return 1; + if (width > w.ws_col) + { + cerr << "The width of the table (" << width << ") is greater then the width of the terminal (" << w.ws_col << ").\n"; + return 1; + } - const bool headerrow = aoptions.headerrow; - const bool headercolumn = aoptions.headercolumn; - const bool tableborder = aoptions.tableborder; - const bool cellborder = aoptions.cellborder; - const unsigned int padding = aoptions.padding; - const char *const title = aoptions.title; - const unsigned int style = aoptions.style; + if (title != nullptr and title[0] != '\0') + cout << wrap(title, w.ws_col) << "\n"; - if (style >= size(styles)) - return 1; + if (tableborder) + { + cout << styles[style][2]; - const size_t rows = array.size(); - const size_t columns = array[0].size(); + for (unsigned int j = 0; j < columns; ++j) + { + for (unsigned int k = 0; k < (2 * padding) + columnwidth[j]; ++k) + cout << styles[style][0]; - int columnwidth[columns]; - for (unsigned int j = 0; j < columns; ++j) - columnwidth[j] = 0; + if (j == (columns - 1)) + cout << styles[style][4] << "\n"; + else if (cellborder or headerrow or (j == 0 and headercolumn)) + cout << styles[style][3]; + else + cout << styles[style][0]; + } + } - int width = 0; - - setlocale(LC_CTYPE, ""); - - for (unsigned int j = 0; j < columns; ++j) - { for (unsigned int i = 0; i < rows; ++i) - { - int cellwidth = strcol(array[i][j].c_str()); - if (cellwidth > columnwidth[j]) - columnwidth[j] = cellwidth; - } - - width += columnwidth[j]; - } - - struct winsize w; - ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); - - if (tableborder or cellborder or headerrow or headercolumn) - width += (((2 * padding) + 1) * columns) + (tableborder ? 1 : -1); - else - width += (2 * padding) * columns; - - if (width > w.ws_col) - { - cerr << "The width of the table (" << width << ") is greater then the width of the terminal (" << w.ws_col << ").\n"; - return 1; - } - - if (title != nullptr and title[0] != '\0') - cout << wrap(title, w.ws_col) << "\n"; - - if (tableborder) - { - cout << styles[style][2]; - - for (unsigned int j = 0; j < columns; ++j) - { - for (unsigned int k = 0; k < (2 * padding) + columnwidth[j]; ++k) - cout << styles[style][0]; - - if (j == (columns - 1)) - cout << styles[style][4] << "\n"; - else if (cellborder or headerrow or (j == 0 and headercolumn)) - cout << styles[style][3]; - else - cout << styles[style][0]; - } - } - - for (unsigned int i = 0; i < rows; ++i) - { - for (unsigned int j = 0; j < columns; ++j) - { - if ((j == 0 and tableborder) or (j > 0 and cellborder) or (i == 0 and j > 0 and headerrow) or (j == 1 and headercolumn)) - cout << styles[style][1]; - else if (tableborder or (i > 0 and j > 0 and headerrow) or (j > 1 and headercolumn)) - cout << " "; - - const int difference = columnwidth[j] - strcol(array[i][j].c_str()); - - if ((i == 0 and headerrow) or (j == 0 and headercolumn)) - { - const int apadding = (difference / 2); - - cout << string(padding + apadding, ' '); - - cout << "\e[1m" << array[i][j] << "\e[22m"; - - cout << string(padding + (difference - apadding), ' '); - } - else - { - cout << string(padding, ' '); - - cout << aoptions.alignment << setw(difference + array[i][j].length()) << array[i][j]; - - cout << string(padding, ' '); - } - } - - if (tableborder) - cout << styles[style][1]; - - cout << "\n"; - - if (tableborder) - { - if (i == (rows - 1)) - cout << styles[style][8]; - else if (cellborder or (i == 0 and headerrow) or headercolumn) - cout << styles[style][5]; - } - - if ((i == (rows - 1) and tableborder) or (i < (rows - 1) and cellborder) or (i == 0 and headerrow) or (i < (rows - 1) and headercolumn)) { for (unsigned int j = 0; j < columns; ++j) { - if ((i == (rows - 1) and tableborder) or (i < (rows - 1) and cellborder) or (i == 0 and headerrow) or (i < (rows - 1) and j == 0 and headercolumn)) - for (unsigned int k = 0; k < (2 * padding) + columnwidth[j]; ++k) - cout << styles[style][0]; - else if (i < (rows - 1) and headercolumn) - cout << string((2 * padding) + columnwidth[j], ' '); + if ((j == 0 and tableborder) or (j > 0 and cellborder) or (i == 0 and j > 0 and headerrow) or (j == 1 and headercolumn)) + cout << styles[style][1]; + else if (tableborder or (i > 0 and j > 0 and headerrow) or (j > 1 and headercolumn)) + cout << " "; - if (j == (columns - 1)) + const int difference = columnwidth[j] - strcol(array[i][j].c_str()); + + if ((i == 0 and headerrow) or (j == 0 and headercolumn)) { - if (tableborder) - { - if (i == (rows - 1)) - cout << styles[style][10]; - else if (cellborder or (i == 0 and headerrow)) - cout << styles[style][7]; - else if (headercolumn) - cout << styles[style][1]; - } + const int apadding = (difference / 2); - cout << "\n"; + cout << string(padding + apadding, ' '); + + cout << "\e[1m" << array[i][j] << "\e[22m"; + + cout << string(padding + (difference - apadding), ' '); } else { - if (i == (rows - 1) and tableborder) - { - if (cellborder or (j == 0 and headercolumn)) - cout << styles[style][9]; - else + cout << string(padding, ' '); + + cout << aoptions.alignment << setw(difference + array[i][j].length()) << array[i][j]; + + cout << string(padding, ' '); + } + } + + if (tableborder) + cout << styles[style][1]; + + cout << "\n"; + + if (tableborder) + { + if (i == (rows - 1)) + cout << styles[style][8]; + else if (cellborder or (i == 0 and headerrow) or headercolumn) + cout << styles[style][5]; + } + + if ((i == (rows - 1) and tableborder) or (i < (rows - 1) and cellborder) or (i == 0 and headerrow) or (i < (rows - 1) and headercolumn)) + { + for (unsigned int j = 0; j < columns; ++j) + { + if ((i == (rows - 1) and tableborder) or (i < (rows - 1) and cellborder) or (i == 0 and headerrow) or (i < (rows - 1) and j == 0 and headercolumn)) + for (unsigned int k = 0; k < (2 * padding) + columnwidth[j]; ++k) cout << styles[style][0]; - } - else if ((i < (rows - 1) and cellborder) or ((i == 0 and headerrow) and (j == 0 and headercolumn))) - cout << styles[style][6]; - else if (i == 0 and headerrow) - cout << styles[style][9]; else if (i < (rows - 1) and headercolumn) + cout << string((2 * padding) + columnwidth[j], ' '); + + if (j == (columns - 1)) { - if (j == 0) - cout << styles[style][7]; - else - cout << " "; + if (tableborder) + { + if (i == (rows - 1)) + cout << styles[style][10]; + else if (cellborder or (i == 0 and headerrow)) + cout << styles[style][7]; + else if (headercolumn) + cout << styles[style][1]; + } + + cout << "\n"; + } + else + { + if (i == (rows - 1) and tableborder) + { + if (cellborder or (j == 0 and headercolumn)) + cout << styles[style][9]; + else + cout << styles[style][0]; + } + else if ((i < (rows - 1) and cellborder) or ((i == 0 and headerrow) and (j == 0 and headercolumn))) + cout << styles[style][6]; + else if (i == 0 and headerrow) + cout << styles[style][9]; + else if (i < (rows - 1) and headercolumn) + { + if (j == 0) + cout << styles[style][7]; + else + cout << " "; + } } } } } + + cout << endl; + + return 0; } - cout << endl; - - return 0; -} - -// Convert array to char array and output as table -template -int table(const T1 &aarray, T2 headerrow[] = nullptr, T2 headercolumn[] = nullptr, const tableoptions &aoptions = defaultoptions) -{ - if (!size(aarray)) - return 1; - - unsigned int i = 0; - unsigned int j = 0; - - size_t rows = size(aarray); - size_t columns = size(aarray[0]); - - if (!all_of(begin(aarray), end(aarray), [columns](auto &x) - { return size(x) == columns; })) + // Convert array to char array and output as table + template + int array(const T1 &aarray, T2 headerrow[] = nullptr, T2 headercolumn[] = nullptr, const options &aoptions = defaultoptions) { - cerr << "Error: The rows of the array must have the same number of columns."; - return 1; + if (!size(aarray)) + return 1; + + unsigned int i = 0; + unsigned int j = 0; + + size_t rows = size(aarray); + size_t columns = size(aarray[0]); + + if (!all_of(begin(aarray), end(aarray), [columns](auto &x) + { return size(x) == columns; })) + { + cerr << "Error: The rows of the array must have the same number of columns."; + return 1; + } + + if (headerrow != nullptr) + ++rows; + + if (headercolumn != nullptr) + ++columns; + + vector> aaarray(rows, vector(columns)); + + if (headerrow != nullptr) + { + for (unsigned int j = 0; j < columns; ++j) + { + aaarray[i][j] = headerrow[j]; + } + + ++i; + } + + for (unsigned int ii = 0; i < rows; ++i) + { + if (headercolumn != nullptr) + { + unsigned int ii = i; + + if (headerrow != nullptr) + --ii; + + aaarray[i][j] = headercolumn[ii]; + + ++j; + } + + for (unsigned int jj = 0; j < columns; ++j) + { + ostringstream strm; + + if (aoptions.boolalpha) + strm << boolalpha; + + strm << aarray[ii][jj]; + aaarray[i][j] = strm.str(); + + ++jj; + } + + j = 0; + ++ii; + } + + return table(aaarray, aoptions); } - if (headerrow != nullptr) - ++rows; - - if (headercolumn != nullptr) - ++columns; - - vector> aaarray(rows, vector(columns)); - - if (headerrow != nullptr) + template + int array(const size_t rows, const size_t columns, T **aarray, const char *const headerrow[] = nullptr, const char *const headercolumn[] = nullptr, const options &aoptions = defaultoptions) { + vector> aaarray(rows, vector(columns)); + for (unsigned int i = 0; i < rows; ++i) + copy(aarray[i], aarray[i] + columns, aaarray[i].begin()); + + string *aheaderrow = nullptr; + string *aheadercolumn = nullptr; + + if (headerrow and headercolumn) + { + vector aaheaderrow(rows + 1); + copy(headerrow, headerrow + rows + 1, aaheaderrow.begin()); + aheaderrow = aaheaderrow.data(); + + vector aaheadercolumn(columns); + copy(headercolumn, headercolumn + columns, aaheadercolumn.begin()); + aheadercolumn = aaheadercolumn.data(); + } + else if (headerrow) + { + vector aaheaderrow(rows); + copy(headerrow, headerrow + rows, aaheaderrow.begin()); + aheaderrow = aaheaderrow.data(); + } + else if (headercolumn) + { + vector aaheadercolumn(columns); + copy(headercolumn, headercolumn + columns, aaheadercolumn.begin()); + aheadercolumn = aaheadercolumn.data(); + } + + return array(aaarray, aheaderrow, aheadercolumn, aoptions); + } + + // Convert one or more functions to array and output as table + template + int functions(const long double xmin, const long double xmax, const long double xscl, const size_t numfunctions, function functions[], const options &aoptions = defaultoptions) + { + if (numfunctions == 0) + return 1; + + if (xmin >= xmax) + { + cerr << "xmin must be less than xmax.\n"; + return 1; + } + + if (xscl <= 0) + { + cerr << "xscl must be greater than zero.\n"; + return 1; + } + + const size_t rows = ((xmax - xmin) * xscl) + 1; + const size_t columns = numfunctions + 1; + + const char *const aheaderrow[] = {"x", "y"}; + // const char* const aheaderrow[] = {"", "x", "y"}; + + const size_t length = size(aheaderrow); + + string *headerrow = new string[columns]; + for (unsigned int j = 0; j < columns; ++j) { - aaarray[i][j] = headerrow[j]; + if (j < (length - 1) or numfunctions == 1) + { + headerrow[j] = aheaderrow[j]; + } + else + { + ostringstream strm; + strm << aheaderrow[length - 1] << j - length + 2; + headerrow[j] = strm.str(); + } } - ++i; - } + string *headercolumn = nullptr; + // headercolumn = new string[rows + 1]; - for (unsigned int ii = 0; i < rows; ++i) - { - if (headercolumn != nullptr) + // for (unsigned int i = 0; i < rows + 1; ++i) + // { + // ostringstream strm; + // strm << i + 1; + // headercolumn[i] = strm.str(); + // } + + vector> aarray(rows, vector(columns)); + + for (unsigned int i = 0; i < rows; ++i) { - unsigned int ii = i; + aarray[i][0] = (i / xscl) + xmin; - if (headerrow != nullptr) - --ii; - - aaarray[i][j] = headercolumn[ii]; - - ++j; + for (unsigned int j = 0; j < numfunctions; ++j) + aarray[i][j + 1] = (functions[j])(aarray[i][0]); } - for (unsigned int jj = 0; j < columns; ++j) + int code = array(aarray, headerrow, headercolumn, aoptions); + + if (headerrow != nullptr) { - ostringstream strm; - - if (aoptions.boolalpha) - strm << boolalpha; - - strm << aarray[ii][jj]; - aaarray[i][j] = strm.str(); - - ++jj; + delete[] headerrow; } - j = 0; - ++ii; + // if (headercolumn != nullptr) + // { + // delete[] headercolumn; + // } + + return code; + } + + // Convert single function to array and output as table + template + int function(const long double xmin, const long double xmax, const long double xscl, const function &afunction, const options &aoptions = defaultoptions) + { + std::function afunctions[] = {afunction}; + + return functions(xmin, xmax, xscl, 1, afunctions, aoptions); + } + + // Convert single function to array and output as table + template + int function(const long double xmin, const long double xmax, const long double xscl, T afunction(T), const options &aoptions = defaultoptions) + { + std::function afunctions[] = {afunction}; + + return functions(xmin, xmax, xscl, 1, afunctions, aoptions); } - return table(aaarray, aoptions); -} - -template -int table(const size_t rows, const size_t columns, T **aarray, const char *const headerrow[] = nullptr, const char *const headercolumn[] = nullptr, const tableoptions &aoptions = defaultoptions) -{ - vector> aaarray(rows, vector(columns)); - for (unsigned int i = 0; i < rows; ++i) - copy(aarray[i], aarray[i] + columns, aaarray[i].begin()); - - string *aheaderrow = nullptr; - string *aheadercolumn = nullptr; - - if (headerrow and headercolumn) - { - vector aaheaderrow(rows + 1); - copy(headerrow, headerrow + rows + 1, aaheaderrow.begin()); - aheaderrow = aaheaderrow.data(); - - vector aaheadercolumn(columns); - copy(headercolumn, headercolumn + columns, aaheadercolumn.begin()); - aheadercolumn = aaheadercolumn.data(); - } - else if (headerrow) - { - vector aaheaderrow(rows); - copy(headerrow, headerrow + rows, aaheaderrow.begin()); - aheaderrow = aaheaderrow.data(); - } - else if (headercolumn) - { - vector aaheadercolumn(columns); - copy(headercolumn, headercolumn + columns, aaheadercolumn.begin()); - aheadercolumn = aaheadercolumn.data(); - } - - return table(aaarray, aheaderrow, aheadercolumn, aoptions); -} - -// Convert one or more functions to array and output as table -template -int table(const long double xmin, const long double xmax, const long double xscl, const size_t numfunctions, function functions[], const tableoptions &aoptions = defaultoptions) -{ - if (numfunctions == 0) - return 1; - - if (xmin >= xmax) - { - cerr << "xmin must be less than xmax.\n"; - return 1; - } - - if (xscl <= 0) - { - cerr << "xscl must be greater than zero.\n"; - return 1; - } - - const size_t rows = ((xmax - xmin) * xscl) + 1; - const size_t columns = numfunctions + 1; - - const char *const aheaderrow[] = {"x", "y"}; - // const char* const aheaderrow[] = {"", "x", "y"}; - - const size_t length = size(aheaderrow); - - string *headerrow = new string[columns]; - - for (unsigned int j = 0; j < columns; ++j) - { - if (j < (length - 1) or numfunctions == 1) - { - headerrow[j] = aheaderrow[j]; - } - else - { - ostringstream strm; - strm << aheaderrow[length - 1] << j - length + 2; - headerrow[j] = strm.str(); - } - } - - string *headercolumn = nullptr; - // headercolumn = new string[rows + 1]; - - // for (unsigned int i = 0; i < rows + 1; ++i) - // { - // ostringstream strm; - // strm << i + 1; - // headercolumn[i] = strm.str(); - // } - - vector> aarray(rows, vector(columns)); - - for (unsigned int i = 0; i < rows; ++i) - { - aarray[i][0] = (i / xscl) + xmin; - - for (unsigned int j = 0; j < numfunctions; ++j) - aarray[i][j + 1] = (functions[j])(aarray[i][0]); - } - - int code = table(aarray, headerrow, headercolumn, aoptions); - - if (headerrow != nullptr) - { - delete[] headerrow; - } - - // if (headercolumn != nullptr) - // { - // delete[] headercolumn; - // } - - return code; -} - -// Convert single function to array and output as table -template -int table(const long double xmin, const long double xmax, const long double xscl, const function &afunction, const tableoptions &aoptions = defaultoptions) -{ - std::function afunctions[] = {afunction}; - - return table(xmin, xmax, xscl, 1, afunctions, aoptions); -} - -// Convert single function to array and output as table -template -int table(const long double xmin, const long double xmax, const long double xscl, T afunction(T), const tableoptions &aoptions = defaultoptions) -{ - std::function afunctions[] = {afunction}; - - return table(xmin, xmax, xscl, 1, afunctions, aoptions); }