From 4761ab105867b9dd2a062c676eb1053f0b4e47d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20Miku=C4=8Dionis?= Date: Wed, 23 Oct 2024 14:08:41 +0200 Subject: [PATCH 1/7] Replaced regex with custom string parsing and a few more low hanging improvements --- source/matplot/backend/backend_interface.h | 26 +++++++- source/matplot/backend/gnuplot.cpp | 75 +++++++++------------- source/matplot/backend/gnuplot.h | 2 +- source/matplot/core/axes_type.cpp | 22 +++---- source/matplot/core/axes_type.h | 12 ++-- source/matplot/core/figure_type.cpp | 3 +- 6 files changed, 75 insertions(+), 65 deletions(-) diff --git a/source/matplot/backend/backend_interface.h b/source/matplot/backend/backend_interface.h index f499310f..460ff82b 100644 --- a/source/matplot/backend/backend_interface.h +++ b/source/matplot/backend/backend_interface.h @@ -41,6 +41,7 @@ namespace matplot { class MATPLOT_EXPORTS backend_interface { /// Virtual functions you can override to create any backend public: + virtual ~backend_interface() noexcept = default; /// \brief True if backend is in interactive mode /// One backends might support both interactive and /// non-interactive mode. @@ -213,7 +214,30 @@ namespace matplot { /// This is useful when tracing the gnuplot commands /// and when generating a gnuplot file. virtual void include_comment(const std::string &text); - }; + }; // backend_interface + /// Captures (backend) version information. + struct Version { + int major{}, minor{}, patch{}; + constexpr bool operator==(const Version &o) const { + return major == o.major && minor == o.minor && patch == o.patch; + } + constexpr bool operator!=(const Version &other) const { return !(*this == other); } + constexpr bool operator<(const Version &other) const { + if (major < other.major) + return true; + else if (major == other.major) { + if (minor < other.minor) + return true; + else if (minor == other.minor) + return patch < other.patch; + } + return false; + } + constexpr bool operator>(const Version &other) const { return other < *this; } + constexpr bool operator<=(const Version &other) const { return !(other < *this); } + constexpr bool operator>=(const Version &other) const { return !(other > *this); } + constexpr operator bool() const { return *this != Version{0,0,0}; } + }; // struct Version } // namespace backend } // namespace matplot diff --git a/source/matplot/backend/gnuplot.cpp b/source/matplot/backend/gnuplot.cpp index 674e1ff2..a4bccf7b 100644 --- a/source/matplot/backend/gnuplot.cpp +++ b/source/matplot/backend/gnuplot.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include @@ -317,13 +317,28 @@ namespace matplot::backend { } } + /// returns the next word in text after prefix terminated with white space. + std::string_view word_after(std::string_view text, std::string_view prefix) + { + auto res = text.substr(0,0); + if (auto b = text.find(prefix); b != std::string_view::npos) { + b += prefix.length(); + while (b < text.length() && std::isspace(text[b])) + ++b; // skip white space before word + auto e = b; + while (e < text.length() && !std::isspace(text[e])) + ++e; // scan until white space or end + res = text.substr(b, e-b); + } + return res; + } + std::string gnuplot::default_terminal_type() { static std::string terminal_type; const bool dont_know_term_type = terminal_type.empty(); if (dont_know_term_type) { terminal_type = run_and_get_output("gnuplot -e \"show terminal\" 2>&1"); - terminal_type = std::regex_replace(terminal_type, - std::regex("[^]*terminal type is ([^ ]+)[^]*"), "$1"); + terminal_type = word_after(terminal_type, "terminal type is "); const bool still_dont_know_term_type = terminal_type.empty(); if (still_dont_know_term_type) { terminal_type = "qt"; @@ -334,51 +349,25 @@ namespace matplot::backend { bool gnuplot::terminal_is_available(std::string_view term) { std::string msg = run_and_get_output("gnuplot -e \"set terminal " + - std::string(term.data()) + "\" 2>&1"); + std::string{term} + "\" 2>&1"); return msg.empty(); } - std::tuple gnuplot::gnuplot_version() { - static std::tuple version{0, 0, 0}; - const bool dont_know_gnuplot_version_yet = - version == std::tuple({0, 0, 0}); - if (dont_know_gnuplot_version_yet) { - std::string version_str = - run_and_get_output("gnuplot --version 2>&1"); - std::string version_major = std::regex_replace( - version_str, - std::regex("[^]*gnuplot (\\d+)\\.\\d+ patchlevel \\d+ *"), - "$1"); - std::string version_minor = std::regex_replace( - version_str, - std::regex("[^]*gnuplot \\d+\\.(\\d+) patchlevel \\d+ *"), - "$1"); - std::string version_patch = std::regex_replace( - version_str, - std::regex("[^]*gnuplot \\d+\\.\\d+ patchlevel (\\d+) *"), - "$1"); - try { - std::get<0>(version) = std::stoi(version_major); - } catch (...) { - std::get<0>(version) = 0; - } - try { - std::get<1>(version) = std::stoi(version_minor); - } catch (...) { - std::get<1>(version) = 0; - } - try { - std::get<2>(version) = std::stoi(version_patch); - } catch (...) { - std::get<2>(version) = 0; - } - const bool still_dont_know_gnuplot_version = - version == std::tuple({0, 0, 0}); - if (still_dont_know_gnuplot_version) { - // assume it's 5.2.6 by convention - version = std::tuple({5, 2, 6}); + Version gnuplot::gnuplot_version() { + static auto version = Version{0, 0, 0}; + if (!version) { + const auto version_str = run_and_get_output("gnuplot --version 2>&1"); + const auto major = word_after(version_str, "gnuplot"); + const auto minor = word_after(major, "."); + const auto patch = word_after(version_str, "patchlevel"); + if (!major.empty() && !minor.empty() && !patch.empty()) { + std::from_chars(major.begin(), major.end(), version.major); + std::from_chars(minor.begin(), minor.end(), version.minor); + std::from_chars(patch.begin(), patch.end(), version.patch); } } + if (!version) + version = {5, 2, 6}; // assume by convention return version; } diff --git a/source/matplot/backend/gnuplot.h b/source/matplot/backend/gnuplot.h index dc74abef..18230da5 100644 --- a/source/matplot/backend/gnuplot.h +++ b/source/matplot/backend/gnuplot.h @@ -47,7 +47,7 @@ namespace matplot::backend { /// Identify the default terminal type in the system static std::string default_terminal_type(); static bool terminal_is_available(std::string_view); - static std::tuple gnuplot_version(); + static Version gnuplot_version(); static bool terminal_has_title_option(const std::string &t); static bool terminal_has_size_option(const std::string &t); static bool terminal_has_position_option(const std::string &t); diff --git a/source/matplot/core/axes_type.cpp b/source/matplot/core/axes_type.cpp index d7594a60..70b91c87 100644 --- a/source/matplot/core/axes_type.cpp +++ b/source/matplot/core/axes_type.cpp @@ -426,7 +426,7 @@ namespace matplot { run_command("set polar"); } auto set_or_unset_axis = [this](class axis_type &ax, - std::string axis_name, + const std::string &axis_name, bool minor_ticks = false) { // cb is the only axis we don't unset if tics are empty // r-axis labels should still be handled even if axis is invisible since we use the grid @@ -694,8 +694,7 @@ namespace matplot { // Gnuplot version needs to be 5.2.6+ for keyentry bool ok = true; if (parent_->backend_->consumes_gnuplot_commands()) { - if (backend::gnuplot::gnuplot_version() < - std::tuple{5, 2, 6}) { + if (backend::gnuplot::gnuplot_version() < backend::Version{5, 2, 6}) { ok = false; } } @@ -916,9 +915,8 @@ namespace matplot { static bool msg_shown_once = false; // Gnuplot version needs to be 5.2.6+ for keyentry if (parent_->backend_->consumes_gnuplot_commands()) { - std::tuple v = - backend::gnuplot::gnuplot_version(); - if (v < std::tuple{5, 2, 6}) { + const auto v = backend::gnuplot::gnuplot_version(); + if (v < backend::Version{5, 2, 6}) { if (!msg_shown_once) { std::cerr << "You need gnuplot 5.2.6+ to include legends" @@ -2745,9 +2743,9 @@ namespace matplot { } std::vector - axes_type::fplot(std::vector equations, - std::array x_range, - std::vector line_specs) { + axes_type::fplot(const std::vector &equations, + const std::array &x_range, + const std::vector &line_specs) { axes_silencer temp_silencer_{this}; std::vector res; auto it_line_specs = line_specs.begin(); @@ -2764,9 +2762,9 @@ namespace matplot { } std::vector - axes_type::fplot(std::vector equations, - std::vector x_range, - std::vector line_specs) { + axes_type::fplot(const std::vector& equations, + const std::vector& x_range, + const std::vector& line_specs) { return this->fplot(equations, to_array<2>(x_range), line_specs); } diff --git a/source/matplot/core/axes_type.h b/source/matplot/core/axes_type.h index 227003f1..caedf10e 100644 --- a/source/matplot/core/axes_type.h +++ b/source/matplot/core/axes_type.h @@ -979,15 +979,15 @@ namespace matplot { /// Lambda function line plot - list of functions std::vector - fplot(std::vector equations, - std::array x_range = {-5, 5}, - std::vector line_specs = {}); + fplot(const std::vector &equations, + const std::array &x_range = {-5, 5}, + const std::vector &line_specs = {}); /// Lambda function line plot - list of functions and line specs std::vector - fplot(std::vector equations, - std::vector x_range, - std::vector line_specs = {}); + fplot(const std::vector &equations, + const std::vector &x_range, + const std::vector &line_specs = {}); using implicit_function_type = std::function; diff --git a/source/matplot/core/figure_type.cpp b/source/matplot/core/figure_type.cpp index a4ff0903..aab3810d 100644 --- a/source/matplot/core/figure_type.cpp +++ b/source/matplot/core/figure_type.cpp @@ -634,8 +634,7 @@ namespace matplot { // In gnuplot 5.5 we have the wall function to set the axes color // with a rectangle workaround, which does not work well for 3d. static const auto v = backend::gnuplot::gnuplot_version(); - const bool has_wall_option = - std::get<0>(v) > 5 || (std::get<0>(v) == 5 && std::get<1>(v) >= 5); + const bool has_wall_option = v >= backend::Version{5,5,0}; // So we only plot the default background if it's not 3d or version is // higher than 5.5. Otherwise, gnuplot won't be able to set the axes // colors. From b5906e2ec87c5417da0bd7a71bdadc30c075284e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20Miku=C4=8Dionis?= Date: Wed, 23 Oct 2024 14:44:00 +0200 Subject: [PATCH 2/7] Fixed from_chars calls --- source/matplot/backend/gnuplot.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/matplot/backend/gnuplot.cpp b/source/matplot/backend/gnuplot.cpp index a4bccf7b..f262504f 100644 --- a/source/matplot/backend/gnuplot.cpp +++ b/source/matplot/backend/gnuplot.cpp @@ -361,9 +361,9 @@ namespace matplot::backend { const auto minor = word_after(major, "."); const auto patch = word_after(version_str, "patchlevel"); if (!major.empty() && !minor.empty() && !patch.empty()) { - std::from_chars(major.begin(), major.end(), version.major); - std::from_chars(minor.begin(), minor.end(), version.minor); - std::from_chars(patch.begin(), patch.end(), version.patch); + std::from_chars(major.data(), major.data()+major.length(), version.major); + std::from_chars(minor.data(), minor.data()+minor.length(), version.minor); + std::from_chars(patch.data(), patch.data()+patch.length(), version.patch); } } if (!version) From 1f5d92c187f37226b6ff7a96462847531d394e92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20Miku=C4=8Dionis?= Date: Thu, 24 Oct 2024 09:40:34 +0200 Subject: [PATCH 3/7] Fixed some code readability --- source/matplot/backend/backend_interface.h | 5 +++-- source/matplot/backend/gnuplot.cpp | 10 +++++----- source/matplot/core/figure_type.cpp | 4 ++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/source/matplot/backend/backend_interface.h b/source/matplot/backend/backend_interface.h index 460ff82b..3f4d56d0 100644 --- a/source/matplot/backend/backend_interface.h +++ b/source/matplot/backend/backend_interface.h @@ -214,10 +214,11 @@ namespace matplot { /// This is useful when tracing the gnuplot commands /// and when generating a gnuplot file. virtual void include_comment(const std::string &text); - }; // backend_interface + }; // class backend_interface + /// Captures (backend) version information. struct Version { - int major{}, minor{}, patch{}; + int major{0}, minor{0}, patch{0}; constexpr bool operator==(const Version &o) const { return major == o.major && minor == o.minor && patch == o.patch; } diff --git a/source/matplot/backend/gnuplot.cpp b/source/matplot/backend/gnuplot.cpp index f262504f..dd0cecf2 100644 --- a/source/matplot/backend/gnuplot.cpp +++ b/source/matplot/backend/gnuplot.cpp @@ -318,7 +318,7 @@ namespace matplot::backend { } /// returns the next word in text after prefix terminated with white space. - std::string_view word_after(std::string_view text, std::string_view prefix) + static std::string_view word_after(std::string_view text, std::string_view prefix) { auto res = text.substr(0,0); if (auto b = text.find(prefix); b != std::string_view::npos) { @@ -354,8 +354,8 @@ namespace matplot::backend { } Version gnuplot::gnuplot_version() { - static auto version = Version{0, 0, 0}; - if (!version) { + static auto version = Version{}; + if (!version) { // unknown version const auto version_str = run_and_get_output("gnuplot --version 2>&1"); const auto major = word_after(version_str, "gnuplot"); const auto minor = word_after(major, "."); @@ -365,9 +365,9 @@ namespace matplot::backend { std::from_chars(minor.data(), minor.data()+minor.length(), version.minor); std::from_chars(patch.data(), patch.data()+patch.length(), version.patch); } + if (!version) // still unknown + version = {5, 2, 6}; // assume by convention } - if (!version) - version = {5, 2, 6}; // assume by convention return version; } diff --git a/source/matplot/core/figure_type.cpp b/source/matplot/core/figure_type.cpp index aab3810d..b5843874 100644 --- a/source/matplot/core/figure_type.cpp +++ b/source/matplot/core/figure_type.cpp @@ -634,7 +634,7 @@ namespace matplot { // In gnuplot 5.5 we have the wall function to set the axes color // with a rectangle workaround, which does not work well for 3d. static const auto v = backend::gnuplot::gnuplot_version(); - const bool has_wall_option = v >= backend::Version{5,5,0}; + const bool has_wall_option = (v >= backend::Version{5,5,0}); // So we only plot the default background if it's not 3d or version is // higher than 5.5. Otherwise, gnuplot won't be able to set the axes // colors. @@ -894,4 +894,4 @@ namespace matplot { bool figure_type::should_close() { return backend_->should_close(); } -} // namespace matplot \ No newline at end of file +} // namespace matplot From 29460e004c37acda26a0ca34010392ed4e20c091 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20Miku=C4=8Dionis?= Date: Thu, 24 Oct 2024 18:44:15 +0200 Subject: [PATCH 4/7] Moved the version-dependent checks into gnuplot scope --- source/matplot/backend/backend_interface.h | 25 ------------------- source/matplot/backend/gnuplot.cpp | 29 +++++++++++++++------- source/matplot/backend/gnuplot.h | 20 ++++++++++++++- source/matplot/core/axes_type.cpp | 7 ++---- source/matplot/core/figure_type.cpp | 3 +-- 5 files changed, 42 insertions(+), 42 deletions(-) diff --git a/source/matplot/backend/backend_interface.h b/source/matplot/backend/backend_interface.h index 3f4d56d0..c4e7442f 100644 --- a/source/matplot/backend/backend_interface.h +++ b/source/matplot/backend/backend_interface.h @@ -215,32 +215,7 @@ namespace matplot { /// and when generating a gnuplot file. virtual void include_comment(const std::string &text); }; // class backend_interface - - /// Captures (backend) version information. - struct Version { - int major{0}, minor{0}, patch{0}; - constexpr bool operator==(const Version &o) const { - return major == o.major && minor == o.minor && patch == o.patch; - } - constexpr bool operator!=(const Version &other) const { return !(*this == other); } - constexpr bool operator<(const Version &other) const { - if (major < other.major) - return true; - else if (major == other.major) { - if (minor < other.minor) - return true; - else if (minor == other.minor) - return patch < other.patch; - } - return false; - } - constexpr bool operator>(const Version &other) const { return other < *this; } - constexpr bool operator<=(const Version &other) const { return !(other < *this); } - constexpr bool operator>=(const Version &other) const { return !(other > *this); } - constexpr operator bool() const { return *this != Version{0,0,0}; } - }; // struct Version } // namespace backend - } // namespace matplot #endif // MATPLOTPLUSPLUS_BACKEND_INTERFACE_H diff --git a/source/matplot/backend/gnuplot.cpp b/source/matplot/backend/gnuplot.cpp index dd0cecf2..1fd8fe9e 100644 --- a/source/matplot/backend/gnuplot.cpp +++ b/source/matplot/backend/gnuplot.cpp @@ -353,24 +353,35 @@ namespace matplot::backend { return msg.empty(); } - Version gnuplot::gnuplot_version() { - static auto version = Version{}; + gnuplot::version_info gnuplot::gnuplot_version() { + static auto version = version_info{}; if (!version) { // unknown version const auto version_str = run_and_get_output("gnuplot --version 2>&1"); - const auto major = word_after(version_str, "gnuplot"); - const auto minor = word_after(major, "."); - const auto patch = word_after(version_str, "patchlevel"); - if (!major.empty() && !minor.empty() && !patch.empty()) { - std::from_chars(major.data(), major.data()+major.length(), version.major); + // gnuplot version_str example: "5.2 patchlevel 6" + const auto major_minor = word_after(version_str, "gnuplot"); // "5.2" + const auto minor = word_after(major_minor, "."); // "2" + const auto patch = word_after(version_str, "patchlevel"); // "6" + if (!major_minor.empty() && !minor.empty() && !patch.empty()) { + std::from_chars(major_minor.data(), major_minor.data()+major_minor.length(), version.major); std::from_chars(minor.data(), minor.data()+minor.length(), version.minor); std::from_chars(patch.data(), patch.data()+patch.length(), version.patch); } - if (!version) // still unknown - version = {5, 2, 6}; // assume by convention + if (!version) // still unknown + version = {5, 2, 6}; // assume by convention } return version; } + bool gnuplot::gnuplot_includes_legends() { + return gnuplot_version() >= version_info{5, 2, 6}; + } + bool gnuplot::gnuplot_has_wall_option() { + return gnuplot_version() >= version_info{5, 5, 0}; + } + bool gnuplot::gnuplot_supports_keyentry() { + return gnuplot_version() >= version_info{5, 2, 6}; + } + bool gnuplot::terminal_has_title_option(const std::string &t) { SV_CONSTEXPR std::string_view whitelist[] = { "qt", "aqua", "caca", "canvas", "windows", "wxt", "x11"}; diff --git a/source/matplot/backend/gnuplot.h b/source/matplot/backend/gnuplot.h index 18230da5..163983d5 100644 --- a/source/matplot/backend/gnuplot.h +++ b/source/matplot/backend/gnuplot.h @@ -44,10 +44,28 @@ namespace matplot::backend { /// We "render the data" by flushing the commands bool flush_commands(); + /// Captures version information. + struct version_info { + int major{0}, minor{0}, patch{0}; + constexpr bool operator==(const version_info &o) const { + return std::tie(major,minor,patch) == std::tie(o.major,o.minor,o.patch); + } + constexpr bool operator!=(const version_info &other) const { return !(*this == other); } + constexpr bool operator<(const version_info &o) const { + return std::tie(major,minor,patch) < std::tie(o.major,o.minor,o.patch); + } + constexpr bool operator>(const version_info &other) const { return other < *this; } + constexpr bool operator<=(const version_info &other) const { return !(other < *this); } + constexpr bool operator>=(const version_info &other) const { return !(other > *this); } + constexpr operator bool() const { return *this != version_info{0,0,0}; } + }; // struct version /// Identify the default terminal type in the system static std::string default_terminal_type(); static bool terminal_is_available(std::string_view); - static Version gnuplot_version(); + static version_info gnuplot_version(); + static bool gnuplot_includes_legends(); + static bool gnuplot_has_wall_option(); + static bool gnuplot_supports_keyentry(); static bool terminal_has_title_option(const std::string &t); static bool terminal_has_size_option(const std::string &t); static bool terminal_has_position_option(const std::string &t); diff --git a/source/matplot/core/axes_type.cpp b/source/matplot/core/axes_type.cpp index 70b91c87..7c057502 100644 --- a/source/matplot/core/axes_type.cpp +++ b/source/matplot/core/axes_type.cpp @@ -694,9 +694,7 @@ namespace matplot { // Gnuplot version needs to be 5.2.6+ for keyentry bool ok = true; if (parent_->backend_->consumes_gnuplot_commands()) { - if (backend::gnuplot::gnuplot_version() < backend::Version{5, 2, 6}) { - ok = false; - } + ok = backend::gnuplot::gnuplot_supports_keyentry(); } if (legend_ == nullptr || !legend_->visible() || !ok) { run_command("set key off"); @@ -915,8 +913,7 @@ namespace matplot { static bool msg_shown_once = false; // Gnuplot version needs to be 5.2.6+ for keyentry if (parent_->backend_->consumes_gnuplot_commands()) { - const auto v = backend::gnuplot::gnuplot_version(); - if (v < backend::Version{5, 2, 6}) { + if (backend::gnuplot::gnuplot_includes_legends()) { if (!msg_shown_once) { std::cerr << "You need gnuplot 5.2.6+ to include legends" diff --git a/source/matplot/core/figure_type.cpp b/source/matplot/core/figure_type.cpp index b5843874..a895d6ea 100644 --- a/source/matplot/core/figure_type.cpp +++ b/source/matplot/core/figure_type.cpp @@ -633,8 +633,7 @@ namespace matplot { void figure_type::run_window_color_command() { // In gnuplot 5.5 we have the wall function to set the axes color // with a rectangle workaround, which does not work well for 3d. - static const auto v = backend::gnuplot::gnuplot_version(); - const bool has_wall_option = (v >= backend::Version{5,5,0}); + const bool has_wall_option = backend::gnuplot::gnuplot_has_wall_option(); // So we only plot the default background if it's not 3d or version is // higher than 5.5. Otherwise, gnuplot won't be able to set the axes // colors. From 86b1dc74e6f79096963db4b08cdc33f1d546d1bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20Miku=C4=8Dionis?= Date: Thu, 24 Oct 2024 18:59:03 +0200 Subject: [PATCH 5/7] Removed struct version in favor of tuple for the sake of old API --- source/matplot/backend/gnuplot.cpp | 21 +++++++++++---------- source/matplot/backend/gnuplot.h | 17 +---------------- 2 files changed, 12 insertions(+), 26 deletions(-) diff --git a/source/matplot/backend/gnuplot.cpp b/source/matplot/backend/gnuplot.cpp index 1fd8fe9e..75d3d14d 100644 --- a/source/matplot/backend/gnuplot.cpp +++ b/source/matplot/backend/gnuplot.cpp @@ -353,33 +353,34 @@ namespace matplot::backend { return msg.empty(); } - gnuplot::version_info gnuplot::gnuplot_version() { - static auto version = version_info{}; - if (!version) { // unknown version + std::tuple gnuplot::gnuplot_version() { + constexpr auto version_zero = std::make_tuple(0, 0, 0); + static auto version = version_zero; + if (version == version_zero) { // unknown version const auto version_str = run_and_get_output("gnuplot --version 2>&1"); // gnuplot version_str example: "5.2 patchlevel 6" const auto major_minor = word_after(version_str, "gnuplot"); // "5.2" const auto minor = word_after(major_minor, "."); // "2" const auto patch = word_after(version_str, "patchlevel"); // "6" if (!major_minor.empty() && !minor.empty() && !patch.empty()) { - std::from_chars(major_minor.data(), major_minor.data()+major_minor.length(), version.major); - std::from_chars(minor.data(), minor.data()+minor.length(), version.minor); - std::from_chars(patch.data(), patch.data()+patch.length(), version.patch); + std::from_chars(major_minor.data(), major_minor.data()+major_minor.length(), std::get<0>(version)); + std::from_chars(minor.data(), minor.data()+minor.length(), std::get<1>(version)); + std::from_chars(patch.data(), patch.data()+patch.length(), std::get<2>(version)); } - if (!version) // still unknown + if (version == version_zero) // still unknown version = {5, 2, 6}; // assume by convention } return version; } bool gnuplot::gnuplot_includes_legends() { - return gnuplot_version() >= version_info{5, 2, 6}; + return gnuplot_version() >= std::make_tuple(5, 2, 6); } bool gnuplot::gnuplot_has_wall_option() { - return gnuplot_version() >= version_info{5, 5, 0}; + return gnuplot_version() >= std::make_tuple(5, 5, 0); } bool gnuplot::gnuplot_supports_keyentry() { - return gnuplot_version() >= version_info{5, 2, 6}; + return gnuplot_version() >= std::make_tuple(5, 2, 6); } bool gnuplot::terminal_has_title_option(const std::string &t) { diff --git a/source/matplot/backend/gnuplot.h b/source/matplot/backend/gnuplot.h index 163983d5..03f8307f 100644 --- a/source/matplot/backend/gnuplot.h +++ b/source/matplot/backend/gnuplot.h @@ -44,25 +44,10 @@ namespace matplot::backend { /// We "render the data" by flushing the commands bool flush_commands(); - /// Captures version information. - struct version_info { - int major{0}, minor{0}, patch{0}; - constexpr bool operator==(const version_info &o) const { - return std::tie(major,minor,patch) == std::tie(o.major,o.minor,o.patch); - } - constexpr bool operator!=(const version_info &other) const { return !(*this == other); } - constexpr bool operator<(const version_info &o) const { - return std::tie(major,minor,patch) < std::tie(o.major,o.minor,o.patch); - } - constexpr bool operator>(const version_info &other) const { return other < *this; } - constexpr bool operator<=(const version_info &other) const { return !(other < *this); } - constexpr bool operator>=(const version_info &other) const { return !(other > *this); } - constexpr operator bool() const { return *this != version_info{0,0,0}; } - }; // struct version /// Identify the default terminal type in the system static std::string default_terminal_type(); static bool terminal_is_available(std::string_view); - static version_info gnuplot_version(); + static std::tuple gnuplot_version(); static bool gnuplot_includes_legends(); static bool gnuplot_has_wall_option(); static bool gnuplot_supports_keyentry(); From c7e74d54c2546924f172c73e5cc602077592717c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20Miku=C4=8Dionis?= Date: Thu, 24 Oct 2024 19:09:47 +0200 Subject: [PATCH 6/7] Formatting --- source/matplot/backend/backend_interface.h | 1 + source/matplot/backend/gnuplot.cpp | 2 +- source/matplot/backend/gnuplot.h | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/source/matplot/backend/backend_interface.h b/source/matplot/backend/backend_interface.h index c4e7442f..21185211 100644 --- a/source/matplot/backend/backend_interface.h +++ b/source/matplot/backend/backend_interface.h @@ -216,6 +216,7 @@ namespace matplot { virtual void include_comment(const std::string &text); }; // class backend_interface } // namespace backend + } // namespace matplot #endif // MATPLOTPLUSPLUS_BACKEND_INTERFACE_H diff --git a/source/matplot/backend/gnuplot.cpp b/source/matplot/backend/gnuplot.cpp index 75d3d14d..b1b23da4 100644 --- a/source/matplot/backend/gnuplot.cpp +++ b/source/matplot/backend/gnuplot.cpp @@ -353,7 +353,7 @@ namespace matplot::backend { return msg.empty(); } - std::tuple gnuplot::gnuplot_version() { + std::tuple gnuplot::gnuplot_version() { constexpr auto version_zero = std::make_tuple(0, 0, 0); static auto version = version_zero; if (version == version_zero) { // unknown version diff --git a/source/matplot/backend/gnuplot.h b/source/matplot/backend/gnuplot.h index 03f8307f..097e19a4 100644 --- a/source/matplot/backend/gnuplot.h +++ b/source/matplot/backend/gnuplot.h @@ -47,7 +47,7 @@ namespace matplot::backend { /// Identify the default terminal type in the system static std::string default_terminal_type(); static bool terminal_is_available(std::string_view); - static std::tuple gnuplot_version(); + static std::tuple gnuplot_version(); static bool gnuplot_includes_legends(); static bool gnuplot_has_wall_option(); static bool gnuplot_supports_keyentry(); From 93a0ff5107322fbe8f8751899e9c1a37a62cb958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20Miku=C4=8Dionis?= Date: Thu, 24 Oct 2024 19:51:17 +0200 Subject: [PATCH 7/7] Fixed readability when converting string_view to int --- source/matplot/backend/gnuplot.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/source/matplot/backend/gnuplot.cpp b/source/matplot/backend/gnuplot.cpp index b1b23da4..b0251b3c 100644 --- a/source/matplot/backend/gnuplot.cpp +++ b/source/matplot/backend/gnuplot.cpp @@ -353,6 +353,11 @@ namespace matplot::backend { return msg.empty(); } + template + void convert_to(std::string_view text, T& value) { + std::from_chars(text.data(), text.data() + text.length(), value); + } + std::tuple gnuplot::gnuplot_version() { constexpr auto version_zero = std::make_tuple(0, 0, 0); static auto version = version_zero; @@ -363,9 +368,9 @@ namespace matplot::backend { const auto minor = word_after(major_minor, "."); // "2" const auto patch = word_after(version_str, "patchlevel"); // "6" if (!major_minor.empty() && !minor.empty() && !patch.empty()) { - std::from_chars(major_minor.data(), major_minor.data()+major_minor.length(), std::get<0>(version)); - std::from_chars(minor.data(), minor.data()+minor.length(), std::get<1>(version)); - std::from_chars(patch.data(), patch.data()+patch.length(), std::get<2>(version)); + convert_to(major_minor, std::get<0>(version)); + convert_to(minor, std::get<1>(version)); + convert_to(patch, std::get<2>(version)); } if (version == version_zero) // still unknown version = {5, 2, 6}; // assume by convention