From ad87fc77fed4880e1cf3dfccf45dab5f9f929f6c Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sun, 10 Dec 2023 07:52:41 -0600 Subject: [PATCH 1/5] Add re2 dependency --- ACKNOWLEDGEMENTS.md | 1 + conanfile.py | 1 + wxdata/wxdata.cmake | 2 ++ 3 files changed, 4 insertions(+) diff --git a/ACKNOWLEDGEMENTS.md b/ACKNOWLEDGEMENTS.md index 27f6686e..f8bdec5d 100644 --- a/ACKNOWLEDGEMENTS.md +++ b/ACKNOWLEDGEMENTS.md @@ -35,6 +35,7 @@ Supercell Wx uses code from the following dependencies: | [nunicode](https://bitbucket.org/alekseyt/nunicode/src/master/) | [MIT License](https://spdx.org/licenses/MIT.html) | Modified for MapLibre Native | | [OpenSSL](https://www.openssl.org/) | [OpenSSL License](https://spdx.org/licenses/OpenSSL.html) | | [Qt](https://www.qt.io/) | [GNU Lesser General Public License v3.0 only](https://spdx.org/licenses/LGPL-3.0-only.html) | Qt Core, Qt GUI, Qt Multimedia, Qt Network, Qt OpenGL, Qt Positioning, Qt SQL, Qt SVG, Qt Widgets
Additional Licenses: https://doc.qt.io/qt-6/licenses-used-in-qt.html | +| [re2](https://github.com/google/re2) | [BSD 3-Clause "New" or "Revised" License](https://spdx.org/licenses/BSD-3-Clause.html) | | [spdlog](https://github.com/gabime/spdlog) | [MIT License](https://spdx.org/licenses/MIT.html) | | [SQLite](https://www.sqlite.org/) | Public Domain | | [stb](https://github.com/nothings/stb) | Public Domain | diff --git a/conanfile.py b/conanfile.py index 9f100e2e..d03504b7 100644 --- a/conanfile.py +++ b/conanfile.py @@ -13,6 +13,7 @@ class SupercellWxConan(ConanFile): "libcurl/8.4.0", "libxml2/2.12.2", "openssl/3.2.0", + "re2/20231101", "spdlog/1.12.0", "sqlite3/3.44.2", "vulkan-loader/1.3.243.0", diff --git a/wxdata/wxdata.cmake b/wxdata/wxdata.cmake index f074d858..25998a11 100644 --- a/wxdata/wxdata.cmake +++ b/wxdata/wxdata.cmake @@ -5,6 +5,7 @@ project(scwx-data) find_package(Boost) find_package(cpr) find_package(LibXml2) +find_package(re2) find_package(spdlog) if (NOT MSVC) @@ -268,6 +269,7 @@ target_link_libraries(wxdata PUBLIC aws-cpp-sdk-core aws-cpp-sdk-s3 cpr::cpr LibXml2::LibXml2 + re2::re2 spdlog::spdlog units::units) target_link_libraries(wxdata INTERFACE Boost::iostreams From 4f309ecb39b77383cd3d04fedae6c920c89452a5 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sun, 10 Dec 2023 21:28:17 -0600 Subject: [PATCH 2/5] Migrate UGC from std::regex to RE2 --- wxdata/source/scwx/awips/ugc.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/wxdata/source/scwx/awips/ugc.cpp b/wxdata/source/scwx/awips/ugc.cpp index 124e13b4..efc6284f 100644 --- a/wxdata/source/scwx/awips/ugc.cpp +++ b/wxdata/source/scwx/awips/ugc.cpp @@ -2,12 +2,12 @@ #include #include -#include #include #include #include #include +#include namespace scwx { @@ -104,10 +104,10 @@ bool Ugc::Parse(const std::vector& ugcString) bool dataValid = false; // UGC takes the form SSFNNN-NNN>NNN-SSFNNN-DDHHMM- (NWSI 10-1702) - static const std::regex reStart {"[A-Z]{2}[CZ]([0-9]{3}|ALL)"}; - static const std::regex reAnyFipsId {"([0-9]{3}|ALL)"}; - static const std::regex reSpecificFipsId {"(?!0{3})[0-9]{3}"}; - static const std::regex reProductExpiration {"[0-9]{6}"}; + static constexpr LazyRE2 reStart = {"[A-Z]{2}[CZ]([0-9]{3}|ALL)"}; + static constexpr LazyRE2 reAnyFipsId = {"([0-9]{3}|ALL)"}; + static constexpr LazyRE2 reSpecificFipsId = {"[0-9]{3}"}; + static constexpr LazyRE2 reProductExpiration = {"[0-9]{6}"}; std::stringstream ugcStream; for (auto& line : ugcString) @@ -131,7 +131,7 @@ bool Ugc::Parse(const std::vector& ugcString) for (auto& token : tokens) { // Product Expiration is the final token - if (std::regex_match(token, reProductExpiration)) + if (RE2::FullMatch(token, *reProductExpiration)) { p->productExpiration_ = token; dataValid = true; @@ -153,7 +153,7 @@ bool Ugc::Parse(const std::vector& ugcString) // Look for the start of the UGC string (may be multiple per UGC string // for multiple states, territories, or marine area) - if (std::regex_match(firstToken, reStart)) + if (RE2::FullMatch(firstToken, *reStart)) { currentState = firstToken.substr(0, 2); currentFormat = ugcFormatMap_.right.at(firstToken.at(2)); @@ -167,7 +167,7 @@ bool Ugc::Parse(const std::vector& ugcString) } // Look for additional FIPS IDs in the UGC string else if (!currentState.empty() && - std::regex_match(firstToken, reAnyFipsId)) + RE2::FullMatch(firstToken, *reAnyFipsId)) { firstFipsId = firstToken; } @@ -188,7 +188,8 @@ bool Ugc::Parse(const std::vector& ugcString) { std::string secondToken {(++tokenIt).current_token()}; - if (std::regex_match(secondToken, reSpecificFipsId)) + if (RE2::FullMatch(secondToken, *reSpecificFipsId) && + secondToken != "000") { secondFipsId = secondToken; } From f612abb846dcc5eb364427a11296814576f57b79 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sun, 10 Dec 2023 21:55:38 -0600 Subject: [PATCH 3/5] Migrate Text Product Message from std::regex to RE2 --- .../scwx/awips/text_product_message.cpp | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/wxdata/source/scwx/awips/text_product_message.cpp b/wxdata/source/scwx/awips/text_product_message.cpp index 9b2a9149..ffbd41dc 100644 --- a/wxdata/source/scwx/awips/text_product_message.cpp +++ b/wxdata/source/scwx/awips/text_product_message.cpp @@ -4,11 +4,11 @@ #include #include -#include #include #include #include +#include namespace scwx { @@ -24,7 +24,7 @@ static const auto logger_ = scwx::util::Logger::Create(logPrefix_); // Segment Header only: // * _xM__day_mon_
_year_/_xM__day_mon_
_year/ // Look for hhmm (xM|UTC) to key the date/time string -static const std::regex reDateTimeString {"^[0-9]{3,4} ([AP]M|UTC)"}; +static constexpr LazyRE2 reDateTimeString = {"^[0-9]{3,4} ([AP]M|UTC)"}; static void ParseCodedInformation(std::shared_ptr segment, const std::string& wfo); @@ -333,7 +333,7 @@ void ParseCodedInformation(std::shared_ptr segment, else if (codedMotionBegin != productContent.cend() && codedMotionEnd == productContent.cend() && !it->starts_with(" ") && - !std::regex_search(*it, std::regex {"^[0-9]"}) + !(it->length() > 0 && std::isdigit(it->at(0))) /* Continuation lines */) { codedMotionEnd = it; @@ -448,7 +448,7 @@ std::vector TryParseMndHeader(std::istream& is) } if (!mndHeader.empty() && - !std::regex_search(mndHeader.back(), reDateTimeString)) + !RE2::PartialMatch(mndHeader.back(), *reDateTimeString)) { // MND Header should end with an Issuance Date/Time Line mndHeader.clear(); @@ -489,8 +489,8 @@ std::optional TryParseSegmentHeader(std::istream& is) // UGC takes the form SSFNNN-NNN>NNN-SSFNNN-DDHHMM- (NWSI 10-1702) // Look for SSF(NNN)?[->] to key the UGC string // Look for DDHHMM- to end the UGC string - static const std::regex reUgcString {"^[A-Z]{2}[CZ]([0-9]{3})?[->]"}; - static const std::regex reUgcExpiration {"[0-9]{6}-$"}; + static constexpr LazyRE2 reUgcString = {"^[A-Z]{2}[CZ]([0-9]{3})?[->]"}; + static constexpr LazyRE2 reUgcExpiration = {"[0-9]{6}-$"}; std::optional header = std::nullopt; std::string line; @@ -498,14 +498,14 @@ std::optional TryParseSegmentHeader(std::istream& is) util::getline(is, line); - if (std::regex_search(line, reUgcString)) + if (RE2::PartialMatch(line, *reUgcString)) { header = SegmentHeader(); header->ugcString_.push_back(line); // If UGC is multi-line, continue parsing while (!is.eof() && is.peek() != '\r' && - !std::regex_search(line, reUgcExpiration)) + !RE2::PartialMatch(line, *reUgcExpiration)) { util::getline(is, line); header->ugcString_.push_back(line); @@ -526,7 +526,7 @@ std::optional TryParseSegmentHeader(std::istream& is) while (!is.eof() && is.peek() != '\r') { util::getline(is, line); - if (!std::regex_search(line, reDateTimeString)) + if (!RE2::PartialMatch(line, *reDateTimeString)) { header->ugcNames_.push_back(line); } @@ -553,12 +553,12 @@ std::optional TryParseVtecString(std::istream& is) // P-VTEC takes the form /k.aaa.cccc.pp.s.####.yymmddThhnnZB-yymmddThhnnZE/ // (NWSI 10-1703) // Look for /k. to key the P-VTEC string - static const std::regex rePVtecString {"^/[OTEX]\\."}; + static constexpr LazyRE2 rePVtecString = {"^/[OTEX]\\."}; // H-VTEC takes the form // /nwsli.s.ic.yymmddThhnnZB.yymmddThhnnZC.yymmddThhnnZE.fr/ (NWSI 10-1703) // Look for /nwsli. to key the H-VTEC string - static const std::regex reHVtecString {"^/[A-Z0-9]{5}\\."}; + static constexpr LazyRE2 reHVtecString = {"^/[A-Z0-9]{5}\\."}; std::optional vtec = std::nullopt; std::string line; @@ -566,7 +566,7 @@ std::optional TryParseVtecString(std::istream& is) util::getline(is, line); - if (std::regex_search(line, rePVtecString)) + if (RE2::PartialMatch(line, *rePVtecString)) { bool vtecValid; @@ -577,7 +577,7 @@ std::optional TryParseVtecString(std::istream& is) util::getline(is, line); - if (std::regex_search(line, reHVtecString)) + if (RE2::PartialMatch(line, *reHVtecString)) { vtec->hVtec_.swap(line); } From 2757c51828c5f5399f3bfe2f0dce3134aa715d8d Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sun, 10 Dec 2023 21:59:32 -0600 Subject: [PATCH 4/5] Migrate Warnings Provider from std::regex to RE2 --- wxdata/source/scwx/provider/warnings_provider.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wxdata/source/scwx/provider/warnings_provider.cpp b/wxdata/source/scwx/provider/warnings_provider.cpp index 6dacc8ea..d187763a 100644 --- a/wxdata/source/scwx/provider/warnings_provider.cpp +++ b/wxdata/source/scwx/provider/warnings_provider.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #if defined(_MSC_VER) @@ -13,6 +12,7 @@ #define LIBXML_HTML_ENABLED #include #include +#include #if !defined(_MSC_VER) # include @@ -77,7 +77,7 @@ WarningsProvider::ListFiles(std::chrono::system_clock::time_point newerThan) using namespace date; #endif - static const std::regex reWarningsFilename { + static constexpr LazyRE2 reWarningsFilename = { "warnings_[0-9]{8}_[0-9]{2}.txt"}; static const std::string dateTimeFormat {"warnings_%Y%m%d_%H.txt"}; @@ -101,7 +101,7 @@ WarningsProvider::ListFiles(std::chrono::system_clock::time_point newerThan) [](auto& record) { return record.type_ == std::filesystem::file_type::regular && - std::regex_match(record.filename_, reWarningsFilename); + RE2::FullMatch(record.filename_, *reWarningsFilename); }); std::unique_lock lock(p->filesMutex_); From 2bd5ec87055c48d7b48ad601f32368a37d5ecc2b Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Mon, 11 Dec 2023 07:07:34 -0600 Subject: [PATCH 5/5] Finish migrating std::regex to RE2 --- .../source/scwx/qt/manager/update_manager.cpp | 14 ++++--------- scwx-qt/source/scwx/qt/map/map_widget.cpp | 18 ++++++++--------- .../scwx/qt/settings/palette_settings.cpp | 7 +++---- test/source/scwx/qt/map/map_provider.test.cpp | 20 +++++++++---------- 4 files changed, 26 insertions(+), 33 deletions(-) diff --git a/scwx-qt/source/scwx/qt/manager/update_manager.cpp b/scwx-qt/source/scwx/qt/manager/update_manager.cpp index 213354ec..08304263 100644 --- a/scwx-qt/source/scwx/qt/manager/update_manager.cpp +++ b/scwx-qt/source/scwx/qt/manager/update_manager.cpp @@ -2,10 +2,10 @@ #include #include -#include #include #include +#include namespace scwx { @@ -61,16 +61,10 @@ std::string UpdateManager::latest_version() const std::string UpdateManager::Impl::GetVersionString(const std::string& releaseName) { - static const std::regex re {"\\d+\\.\\d+\\.\\d+"}; - std::string versionString {}; - std::smatch m; + static constexpr LazyRE2 re = {"(\\d+\\.\\d+\\.\\d+)"}; + std::string versionString {}; - std::regex_search(releaseName, m, re); - - if (!m.empty()) - { - versionString = m[0].str(); - } + RE2::PartialMatch(releaseName, *re, &versionString); return versionString; } diff --git a/scwx-qt/source/scwx/qt/map/map_widget.cpp b/scwx-qt/source/scwx/qt/map/map_widget.cpp index a897748b..ebef32e7 100644 --- a/scwx-qt/source/scwx/qt/map/map_widget.cpp +++ b/scwx-qt/source/scwx/qt/map/map_widget.cpp @@ -23,7 +23,6 @@ #include #include -#include #include #include @@ -33,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -769,14 +769,14 @@ std::string MapWidgetImpl::FindMapSymbologyLayer() const std::string layer = qlayer.toStdString(); // Draw below layers defined in map style - auto it = std::find_if( - currentStyle_->drawBelow_.cbegin(), - currentStyle_->drawBelow_.cend(), - [&layer](const std::string& styleLayer) -> bool - { - std::regex re {styleLayer, std::regex_constants::icase}; - return std::regex_match(layer, re); - }); + auto it = std::find_if(currentStyle_->drawBelow_.cbegin(), + currentStyle_->drawBelow_.cend(), + [&layer](const std::string& styleLayer) -> bool + { + // Perform case-insensitive matching + RE2 re {"(?i)" + styleLayer}; + return RE2::FullMatch(layer, re); + }); if (it != currentStyle_->drawBelow_.cend()) { diff --git a/scwx-qt/source/scwx/qt/settings/palette_settings.cpp b/scwx-qt/source/scwx/qt/settings/palette_settings.cpp index 8133a452..dcf58f2e 100644 --- a/scwx-qt/source/scwx/qt/settings/palette_settings.cpp +++ b/scwx-qt/source/scwx/qt/settings/palette_settings.cpp @@ -2,10 +2,9 @@ #include #include -#include - #include #include +#include namespace scwx { @@ -134,8 +133,8 @@ public: bool PaletteSettings::Impl::ValidateColor(const std::string& value) { - static const std::regex re {"#[0-9A-Za-z]{8}"}; - return std::regex_match(value, re); + static constexpr LazyRE2 re = {"#[0-9A-Fa-f]{8}"}; + return RE2::FullMatch(value, *re); } PaletteSettings::PaletteSettings() : diff --git a/test/source/scwx/qt/map/map_provider.test.cpp b/test/source/scwx/qt/map/map_provider.test.cpp index f3883992..8b330de9 100644 --- a/test/source/scwx/qt/map/map_provider.test.cpp +++ b/test/source/scwx/qt/map/map_provider.test.cpp @@ -2,13 +2,12 @@ #include #include -#include - #include #include #include #include +#include namespace scwx { @@ -108,14 +107,15 @@ TEST_P(ByMapProviderTest, MapProviderLayers) const std::string layer = qlayer.toStdString(); // Draw below layers defined in map style - auto it = std::find_if( - mapStyle.drawBelow_.cbegin(), - mapStyle.drawBelow_.cend(), - [&layer](const std::string& styleLayer) -> bool - { - std::regex re {styleLayer, std::regex_constants::icase}; - return std::regex_match(layer, re); - }); + auto it = + std::find_if(mapStyle.drawBelow_.cbegin(), + mapStyle.drawBelow_.cend(), + [&layer](const std::string& styleLayer) -> bool + { + // Perform case insensitive matching + RE2 re {"(?i)" + styleLayer}; + return RE2::FullMatch(layer, re); + }); if (it != mapStyle.drawBelow_.cend()) {