diff --git a/include/vcpkg/base/strings.h b/include/vcpkg/base/strings.h index 6e7177f8fd..99a2f93336 100644 --- a/include/vcpkg/base/strings.h +++ b/include/vcpkg/base/strings.h @@ -14,6 +14,10 @@ #include #include +#ifdef __APPLE__ +#include +#endif + namespace vcpkg::Strings::details { void append_internal(std::string& into, char c); @@ -43,6 +47,12 @@ namespace vcpkg::Strings::details namespace vcpkg::Strings { +#ifdef __APPLE__ + using boyer_moore_horspool_searcher = std::experimental::boyer_moore_horspool_searcher; +#else + using boyer_moore_horspool_searcher = std::boyer_moore_horspool_searcher; +#endif + template std::string& append(std::string& into, const Args&... args) { @@ -169,11 +179,11 @@ namespace vcpkg::Strings StringView left_tag, StringView right_tag); - bool contains_any_ignoring_c_comments(const std::string& source, View to_find); + bool contains_any_ignoring_c_comments(const std::string& source, View to_find); - bool contains_any_ignoring_hash_comments(StringView source, View to_find); + bool contains_any_ignoring_hash_comments(StringView source, View to_find); - bool contains_any(StringView source, View to_find); + bool long_string_contains_any(StringView source, View to_find); [[nodiscard]] bool equals(StringView a, StringView b); diff --git a/src/vcpkg-test/strings.cpp b/src/vcpkg-test/strings.cpp index 14ff010fec..6313e7113e 100644 --- a/src/vcpkg-test/strings.cpp +++ b/src/vcpkg-test/strings.cpp @@ -72,7 +72,12 @@ TEST_CASE ("find_first_of", "[strings]") TEST_CASE ("contains_any_ignoring_c_comments", "[strings]") { using vcpkg::Strings::contains_any_ignoring_c_comments; - vcpkg::StringView to_find[] = {"abc", "wer"}; + std::string a = "abc"; + std::string b = "wer"; + + vcpkg::Strings::boyer_moore_horspool_searcher to_find[] = { + vcpkg::Strings::boyer_moore_horspool_searcher(a.begin(), a.end()), + vcpkg::Strings::boyer_moore_horspool_searcher(b.begin(), b.end())}; REQUIRE(contains_any_ignoring_c_comments(R"(abc)", to_find)); REQUIRE(contains_any_ignoring_c_comments(R"("abc")", to_find)); REQUIRE_FALSE(contains_any_ignoring_c_comments(R"("" //abc)", to_find)); @@ -127,7 +132,12 @@ TEST_CASE ("contains_any_ignoring_c_comments", "[strings]") TEST_CASE ("contains_any_ignoring_hash_comments", "[strings]") { using vcpkg::Strings::contains_any_ignoring_hash_comments; - vcpkg::StringView to_find[] = {"abc", "wer"}; + std::string a = "abc"; + std::string b = "wer"; + + vcpkg::Strings::boyer_moore_horspool_searcher to_find[] = { + vcpkg::Strings::boyer_moore_horspool_searcher(a.begin(), a.end()), + vcpkg::Strings::boyer_moore_horspool_searcher(b.begin(), b.end())}; REQUIRE(contains_any_ignoring_hash_comments("abc", to_find)); REQUIRE(contains_any_ignoring_hash_comments("wer", to_find)); REQUIRE(contains_any_ignoring_hash_comments("wer # test", to_find)); diff --git a/src/vcpkg/base/strings.cpp b/src/vcpkg/base/strings.cpp index cf7e2e2f9d..e846780f97 100644 --- a/src/vcpkg/base/strings.cpp +++ b/src/vcpkg/base/strings.cpp @@ -380,7 +380,8 @@ Optional Strings::find_at_most_one_enclosed(StringView input, String return result.front(); } -bool vcpkg::Strings::contains_any_ignoring_c_comments(const std::string& source, View to_find) +bool vcpkg::Strings::contains_any_ignoring_c_comments(const std::string& source, + View to_find) { std::string::size_type offset = 0; std::string::size_type no_comment_offset = 0; @@ -390,14 +391,14 @@ bool vcpkg::Strings::contains_any_ignoring_c_comments(const std::string& source, auto start = source.find_first_of("/\"", no_comment_offset); if (start == std::string::npos || start + 1 == source.size() || no_comment_offset == std::string::npos) { - return Strings::contains_any(StringView(source).substr(offset), to_find); + return Strings::long_string_contains_any(StringView(source).substr(offset), to_find); } if (source[start] == '/') { if (source[start + 1] == '/' || source[start + 1] == '*') { - if (Strings::contains_any(StringView(source).substr(offset, start - offset), to_find)) + if (Strings::long_string_contains_any(StringView(source).substr(offset, start - offset), to_find)) { return true; } @@ -444,7 +445,7 @@ bool vcpkg::Strings::contains_any_ignoring_c_comments(const std::string& source, return false; } -bool Strings::contains_any_ignoring_hash_comments(StringView source, View to_find) +bool Strings::contains_any_ignoring_hash_comments(StringView source, View to_find) { auto first = source.data(); auto block_start = first; @@ -453,7 +454,7 @@ bool Strings::contains_any_ignoring_hash_comments(StringView source, View to_find) +bool Strings::long_string_contains_any(StringView source, View to_find) { - return Util::any_of(to_find, [=](StringView s) { return Strings::contains(source, s); }); + for (const auto& subject : to_find) + { + auto found = std::search(source.begin(), source.end(), subject); + if (found != source.end()) + { + return true; + } + } + return false; } bool Strings::equals(StringView a, StringView b) diff --git a/src/vcpkg/postbuildlint.cpp b/src/vcpkg/postbuildlint.cpp index 390d1a3006..a5b9f7db4d 100644 --- a/src/vcpkg/postbuildlint.cpp +++ b/src/vcpkg/postbuildlint.cpp @@ -1222,25 +1222,25 @@ namespace vcpkg static bool file_contains_absolute_paths(const ReadOnlyFilesystem& fs, const Path& file, - const std::vector stringview_paths) + View searcher_paths) { const auto extension = file.extension(); if (extension == ".h" || extension == ".hpp" || extension == ".hxx") { - return Strings::contains_any_ignoring_c_comments(fs.read_contents(file, IgnoreErrors{}), stringview_paths); + return Strings::contains_any_ignoring_c_comments(fs.read_contents(file, IgnoreErrors{}), searcher_paths); } if (extension == ".cfg" || extension == ".ini" || file.filename() == "usage") { const auto contents = fs.read_contents(file, IgnoreErrors{}); - return Strings::contains_any(contents, stringview_paths); + return Strings::long_string_contains_any(contents, searcher_paths); } if (extension == ".py" || extension == ".sh" || extension == ".cmake" || extension == ".pc" || extension == ".conf") { const auto contents = fs.read_contents(file, IgnoreErrors{}); - return Strings::contains_any_ignoring_hash_comments(contents, stringview_paths); + return Strings::contains_any_ignoring_hash_comments(contents, searcher_paths); } if (extension.empty()) @@ -1254,7 +1254,7 @@ namespace vcpkg Strings::starts_with(StringView(buffer, sizeof(buffer)), "\xEF\xBB\xBF#!") /* ignore byte-order mark */) { const auto contents = fs.read_contents(file, IgnoreErrors{}); - return Strings::contains_any_ignoring_hash_comments(contents, stringview_paths); + return Strings::contains_any_ignoring_hash_comments(contents, searcher_paths); } return false; } @@ -1283,14 +1283,15 @@ namespace vcpkg Util::sort_unique_erase(string_paths); - const auto stringview_paths = Util::fmap(string_paths, [](std::string& s) { return StringView(s); }); + const auto searcher_paths = Util::fmap( + string_paths, [](std::string& s) { return Strings::boyer_moore_horspool_searcher(s.begin(), s.end()); }); std::vector failing_files; std::mutex mtx; auto files = fs.get_regular_files_recursive(dir, IgnoreErrors{}); parallel_for_each_n(files.begin(), files.size(), [&](const Path& file) { - if (file_contains_absolute_paths(fs, file, stringview_paths)) + if (file_contains_absolute_paths(fs, file, searcher_paths)) { std::lock_guard lock{mtx}; failing_files.push_back(file);