summaryrefslogtreecommitdiff
path: root/src/glob_matching.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/glob_matching.h')
-rw-r--r--src/glob_matching.h314
1 files changed, 143 insertions, 171 deletions
diff --git a/src/glob_matching.h b/src/glob_matching.h
index e7e7b621..b47d30ac 100644
--- a/src/glob_matching.h
+++ b/src/glob_matching.h
@@ -6,208 +6,180 @@
#ifndef GLOB_MATCHING_H
#define GLOB_MATCHING_H
+#include <QString>
#include <cctype>
#include <string_view>
-#include <QString>
-
-namespace MOShared {
- /**
- * Contraints string_traits to allow usage of both standard strings and QString in
- * GlobPattern.
- */
- namespace details {
+namespace MOShared
+{
- template <
- class CharT,
- class Traits = std::char_traits<CharT>,
- class Allocator = std::allocator<CharT>>
- struct string_traits {
- using string_type = std::basic_string<CharT, Traits, Allocator>;
- using string_view = std::basic_string_view<CharT, Traits>;
+/**
+ * Contraints string_traits to allow usage of both standard strings and QString in
+ * GlobPattern.
+ */
+namespace details
+{
- static auto tolower(CharT c) { return std::tolower(c); }
+ template <class CharT, class Traits = std::char_traits<CharT>,
+ class Allocator = std::allocator<CharT>>
+ struct string_traits
+ {
+ using string_type = std::basic_string<CharT, Traits, Allocator>;
+ using string_view = std::basic_string_view<CharT, Traits>;
- static auto empty(string_view const& view) { return view.empty(); }
- };
+ static auto tolower(CharT c) { return std::tolower(c); }
- template <>
- struct string_traits<QChar> {
- using string_type = QString;
- using string_view = QString;
-
- static auto tolower(QChar const& c) { return c.toLower(); }
- static auto empty(string_view const& view) { return view.isEmpty(); }
- };
+ static auto empty(string_view const& view) { return view.empty(); }
+ };
- }
+ template <>
+ struct string_traits<QChar>
+ {
+ using string_type = QString;
+ using string_view = QString;
- /**
- * @brief Class that provides basic wildcard pattern matching.
- *
- * From https://gitlab.com/G_ka/playground/-/commits/master/include/wildcards.hpp
- *
- * Currently, this supports the following globbing character:
- * - '*' matches zero or more characters.
- * - '?' matches exactly one character.
- * - '[abc]' matches one of 'a', 'b' or 'c'.
- *
- * Standard globbing feature not supported:
- * - You cannot escape globbing characters with \.
- * - You cannot use `[a-z]` to match any character from 'a' to 'z'.
- *
- * Custom class because the following alternatives have some issues:
- * - QRegExp is a tad slow, and we need to convert everything to QString.
- * - QDir::match is VERY slow. I think it converts the glob pattern to a QRegularExpression and
- * then use it.
- * - PatchMatchSpecW (Windows API) is fast but does not support some useful glob pattern (e.g.,
- * [ab]).
- *
- * Advantage of this over the above methods:
- * - It is fast. Quick testing show that this is faster than PatchMatchSpecW.
- * - It can be used on most string types (QString, std::string, std::wstring, etc.).
- */
- template <
- class CharT,
- class Traits = std::char_traits<CharT>,
- class Allocator = std::allocator<CharT>>
- class GlobPattern {
- public:
+ static auto tolower(QChar const& c) { return c.toLower(); }
+ static auto empty(string_view const& view) { return view.isEmpty(); }
+ };
- using traits = details::string_traits<CharT, Traits, Allocator>;
+} // namespace details
- using string_type = typename traits::string_type;
- using string_view_type = typename traits::string_view;
+/**
+ * @brief Class that provides basic wildcard pattern matching.
+ *
+ * From https://gitlab.com/G_ka/playground/-/commits/master/include/wildcards.hpp
+ *
+ * Currently, this supports the following globbing character:
+ * - '*' matches zero or more characters.
+ * - '?' matches exactly one character.
+ * - '[abc]' matches one of 'a', 'b' or 'c'.
+ *
+ * Standard globbing feature not supported:
+ * - You cannot escape globbing characters with \.
+ * - You cannot use `[a-z]` to match any character from 'a' to 'z'.
+ *
+ * Custom class because the following alternatives have some issues:
+ * - QRegExp is a tad slow, and we need to convert everything to QString.
+ * - QDir::match is VERY slow. I think it converts the glob pattern to a
+ * QRegularExpression and then use it.
+ * - PatchMatchSpecW (Windows API) is fast but does not support some useful glob
+ * pattern (e.g., [ab]).
+ *
+ * Advantage of this over the above methods:
+ * - It is fast. Quick testing show that this is faster than PatchMatchSpecW.
+ * - It can be used on most string types (QString, std::string, std::wstring, etc.).
+ */
+template <class CharT, class Traits = std::char_traits<CharT>,
+ class Allocator = std::allocator<CharT>>
+class GlobPattern
+{
+public:
+ using traits = details::string_traits<CharT, Traits, Allocator>;
- struct card {
- // Relying on automatic conversion:
- static constexpr CharT any = '?';
- static constexpr CharT any_repeat = '*';
- static constexpr CharT set_begin = '[';
- static constexpr CharT set_end = ']';
- };
+ using string_type = typename traits::string_type;
+ using string_view_type = typename traits::string_view;
- public:
+ struct card
+ {
+ // Relying on automatic conversion:
+ static constexpr CharT any = '?';
+ static constexpr CharT any_repeat = '*';
+ static constexpr CharT set_begin = '[';
+ static constexpr CharT set_end = ']';
+ };
- GlobPattern(string_view_type const& s) : v{ s } { }
+public:
+ GlobPattern(string_view_type const& s) : v{s} {}
- const string_type& native() const { return v; }
+ const string_type& native() const { return v; }
- constexpr bool match(
- string_view_type const& str,
- bool case_sensitive = false)
- {
- // Empty pattern can only match with empty sting
- if (traits::empty(v))
- return traits::empty(str);
+ constexpr bool match(string_view_type const& str, bool case_sensitive = false)
+ {
+ // Empty pattern can only match with empty sting
+ if (traits::empty(v))
+ return traits::empty(str);
- auto pat_it = v.begin();
- auto pat_end = v.end();
+ auto pat_it = v.begin();
+ auto pat_end = v.end();
- auto str_it = str.begin();
- auto str_end = str.end();
+ auto str_it = str.begin();
+ auto str_end = str.end();
- auto anyrep_pos_pat = pat_end;
- auto anyrep_pos_str = str_end;
+ auto anyrep_pos_pat = pat_end;
+ auto anyrep_pos_str = str_end;
- auto set_pos_pat = pat_end;
+ auto set_pos_pat = pat_end;
- while (str_it != str_end)
- {
- CharT current_pat = QChar(0);
- CharT current_str = QChar(-1);
- if (pat_it != pat_end)
- {
- current_pat = case_sensitive ? *pat_it : traits::tolower(*pat_it);
- current_str = case_sensitive ? *str_it : traits::tolower(*str_it);
- }
- if (pat_it != pat_end && current_pat == card::set_begin)
- {
- set_pos_pat = pat_it;
- pat_it++;
- }
- else if (pat_it != pat_end && current_pat == card::set_end)
- {
- if (anyrep_pos_pat != pat_end)
- {
- set_pos_pat = pat_end;
- pat_it++;
- }
- else
- {
- return false;
- }
+ while (str_it != str_end) {
+ CharT current_pat = QChar(0);
+ CharT current_str = QChar(-1);
+ if (pat_it != pat_end) {
+ current_pat = case_sensitive ? *pat_it : traits::tolower(*pat_it);
+ current_str = case_sensitive ? *str_it : traits::tolower(*str_it);
+ }
+ if (pat_it != pat_end && current_pat == card::set_begin) {
+ set_pos_pat = pat_it;
+ pat_it++;
+ } else if (pat_it != pat_end && current_pat == card::set_end) {
+ if (anyrep_pos_pat != pat_end) {
+ set_pos_pat = pat_end;
+ pat_it++;
+ } else {
+ return false;
+ }
- }
- else if (set_pos_pat != pat_end)
- {
- if (current_pat == current_str)
- {
- set_pos_pat = pat_end;
- pat_it = std::find(pat_it, pat_end, card::set_end) + 1;
- str_it++;
- }
- else
- {
- if (pat_it == pat_end)
- {
- return false;
- }
- pat_it++;
- }
- }
- else if (pat_it != pat_end && current_pat == current_str)
- {
- pat_it++;
- str_it++;
- }
- else if (pat_it != pat_end && current_pat == card::any)
- {
- pat_it++;
- str_it++;
- }
- else if (pat_it != pat_end && current_pat == card::any_repeat)
- {
- anyrep_pos_pat = pat_it;
- anyrep_pos_str = str_it;
- pat_it++;
- }
- else if (anyrep_pos_pat != pat_end)
- {
- pat_it = anyrep_pos_pat + 1;
- str_it = anyrep_pos_str + 1;
- anyrep_pos_str++;
- }
- else
- {
+ } else if (set_pos_pat != pat_end) {
+ if (current_pat == current_str) {
+ set_pos_pat = pat_end;
+ pat_it = std::find(pat_it, pat_end, card::set_end) + 1;
+ str_it++;
+ } else {
+ if (pat_it == pat_end) {
return false;
}
+ pat_it++;
}
- while (pat_it != pat_end)
- {
- CharT cur = case_sensitive ? *pat_it : traits::tolower(*pat_it);
- if (cur == card::any_repeat)
- pat_it++;
- else
- break;
- }
- return pat_it == pat_end;
+ } else if (pat_it != pat_end && current_pat == current_str) {
+ pat_it++;
+ str_it++;
+ } else if (pat_it != pat_end && current_pat == card::any) {
+ pat_it++;
+ str_it++;
+ } else if (pat_it != pat_end && current_pat == card::any_repeat) {
+ anyrep_pos_pat = pat_it;
+ anyrep_pos_str = str_it;
+ pat_it++;
+ } else if (anyrep_pos_pat != pat_end) {
+ pat_it = anyrep_pos_pat + 1;
+ str_it = anyrep_pos_str + 1;
+ anyrep_pos_str++;
+ } else {
+ return false;
}
+ }
+ while (pat_it != pat_end) {
+ CharT cur = case_sensitive ? *pat_it : traits::tolower(*pat_it);
+ if (cur == card::any_repeat)
+ pat_it++;
+ else
+ break;
+ }
+ return pat_it == pat_end;
+ }
- private:
- string_type v;
- };
+private:
+ string_type v;
+};
- template <class CharT, class Traits, class Allocator>
- GlobPattern(std::basic_string<CharT, Traits, Allocator> const&)
+template <class CharT, class Traits, class Allocator>
+GlobPattern(std::basic_string<CharT, Traits, Allocator> const&)
-> GlobPattern<CharT, Traits, Allocator>;
- template <class CharT>
- GlobPattern(CharT const*) -> GlobPattern<CharT>;
-
- GlobPattern(QString const&) -> GlobPattern<QChar>;
+template <class CharT>
+GlobPattern(CharT const*) -> GlobPattern<CharT>;
+GlobPattern(QString const&)->GlobPattern<QChar>;
-} // namespace wildcards
+} // namespace MOShared
#endif