8#include "algorithm.hpp"
14namespace hi::inline v1 {
16enum class glob_token_type_t {
30 case glob_token_type_t::String: lhs <<
"String";
break;
31 case glob_token_type_t::StringList: lhs <<
"StringList";
break;
32 case glob_token_type_t::CharacterList: lhs <<
"CharacterList";
break;
33 case glob_token_type_t::InverseCharacterList: lhs <<
"InverseCharacterList";
break;
34 case glob_token_type_t::Separator: lhs <<
"Separator";
break;
35 case glob_token_type_t::AnyString: lhs <<
"AnyString";
break;
36 case glob_token_type_t::AnyCharacter: lhs <<
"AnyCharacter";
break;
37 case glob_token_type_t::AnyDirectory: lhs <<
"AnyDirectory";
break;
38 default: hi_no_default();
44 glob_token_type_t type;
48 glob_token_t(glob_token_type_t type) : type(type), value(), values() {}
54using glob_token_iterator = glob_token_list_t::iterator;
55using glob_token_const_iterator = glob_token_list_t::const_iterator;
59 return lhs.type == rhs.type && lhs.value == rhs.value && lhs.values == rhs.values;
65 if (rhs.value.size() > 0) {
66 lhs <<
":" << rhs.value;
67 }
else if (rhs.values.size() > 0) {
69 for (
std::size_t i = 0; i < rhs.values.size(); i++) {
99inline glob_token_list_t parseGlob(std::string_view glob)
107 FoundSlashDoubleStar,
111 state_t state = state_t::Idle;
116 bool isInverse =
false;
117 bool isFirstCharacter =
false;
118 bool isRange =
false;
120 auto i = glob.begin();
122 auto c = (i != glob.end()) ? *i :
'\0';
127 case '/': state = state_t::FoundSlash;
break;
128 case '?': r.emplace_back(glob_token_type_t::AnyCharacter);
break;
129 case '*': r.emplace_back(glob_token_type_t::AnyString);
break;
132 isFirstCharacter =
true;
134 state = state_t::FoundBracket;
136 case '{': state = state_t::FoundBrace;
break;
137 case '\\': state = state_t::FoundEscape;
break;
139 default: state = state_t::FoundText;
continue;
143 case state_t::FoundText:
144 if (c ==
'/' || c ==
'?' || c ==
'*' || c ==
'[' || c ==
'{' || c ==
'\0') {
145 r.emplace_back(glob_token_type_t::String, tmpString);
147 state = state_t::Idle;
149 }
else if (c ==
'\\') {
150 state = state_t::FoundEscape;
156 case state_t::FoundEscape:
158 r.emplace_back(glob_token_type_t::String, tmpString);
159 state = state_t::Idle;
163 state = state_t::FoundText;
167 case state_t::FoundSlash:
169 state = state_t::FoundSlashStar;
171 r.emplace_back(glob_token_type_t::Separator);
172 state = state_t::Idle;
177 case state_t::FoundSlashStar:
179 state = state_t::FoundSlashDoubleStar;
181 r.emplace_back(glob_token_type_t::Separator);
182 r.emplace_back(glob_token_type_t::AnyString);
183 state = state_t::Idle;
188 case state_t::FoundSlashDoubleStar:
190 r.emplace_back(glob_token_type_t::AnyDirectory);
191 r.emplace_back(glob_token_type_t::Separator);
192 state = state_t::Idle;
196 r.emplace_back(glob_token_type_t::Separator);
197 r.emplace_back(glob_token_type_t::AnyString);
198 state = state_t::Idle;
203 case state_t::FoundBracket:
206 if (isFirstCharacter) {
215 if (isFirstCharacter) {
223 r.emplace_back(glob_token_type_t::InverseCharacterList, tmpString);
225 r.emplace_back(glob_token_type_t::CharacterList, tmpString);
229 state = state_t::Idle;
231 isFirstCharacter =
false;
235 if (isFirstCharacter) {
240 isFirstCharacter =
false;
249 r.emplace_back(glob_token_type_t::InverseCharacterList, tmpString);
251 r.emplace_back(glob_token_type_t::CharacterList, tmpString);
253 state = state_t::Idle;
258 hilet firstCharacter =
static_cast<uint8_t
>(tmpString.
back());
259 hilet lastCharacter =
static_cast<uint8_t
>(c);
260 for (uint8_t character = firstCharacter + 1; character <= lastCharacter; character++) {
261 tmpString +=
static_cast<char>(character);
267 isFirstCharacter =
false;
272 case state_t::FoundBrace:
277 r.emplace_back(glob_token_type_t::StringList, tmpStringList);
278 tmpStringList.
clear();
279 state = state_t::Idle;
287 r.emplace_back(glob_token_type_t::StringList, tmpStringList);
288 state = state_t::Idle;
290 default: tmpString += c;
break;
294 default: hi_no_default();
301enum class glob_match_result_t { No, Partial, Match };
303inline glob_match_result_t matchGlob(glob_token_const_iterator index, glob_token_const_iterator end, std::string_view str)
306 return (str.size() == 0) ? glob_match_result_t::Match : glob_match_result_t::No;
308 }
else if (str.size() == 0) {
309 switch (index->type) {
310 case glob_token_type_t::Separator:
return glob_match_result_t::Partial;
311 case glob_token_type_t::AnyDirectory:
return glob_match_result_t::Partial;
312 case glob_token_type_t::AnyString:
return matchGlob(index + 1, end, str);
313 default:
return glob_match_result_t::No;
317#define MATCH_GLOB_RECURSE(out, next, end, str) \
318 switch (hilet tmp = matchGlob(next, end, str)) { \
319 case glob_match_result_t::No: break; \
320 case glob_match_result_t::Match: return tmp; \
321 case glob_match_result_t::Partial: out = tmp; break; \
322 default: hi_no_default(); \
326 auto result = glob_match_result_t::No;
327 bool found_slash =
false;
328 hilet next_index = index + 1;
330 switch (index->type) {
331 case glob_token_type_t::String:
332 if (str.starts_with(index->value)) {
333 MATCH_GLOB_RECURSE(result, next_index, end, str.substr(index->value.size()));
337 case glob_token_type_t::StringList:
338 for (
hilet &value : index->values) {
339 if (str.starts_with(value)) {
340 MATCH_GLOB_RECURSE(result, next_index, end, str.substr(value.size()));
345 case glob_token_type_t::CharacterList:
346 if (index->value.find(str.front()) != std::string::npos) {
347 MATCH_GLOB_RECURSE(result, next_index, end, str.substr(1));
351 case glob_token_type_t::InverseCharacterList:
352 if (index->value.find(str.front()) == std::string::npos) {
353 MATCH_GLOB_RECURSE(result, next_index, end, str.substr(1));
357 case glob_token_type_t::Separator:
358 if (str.front() ==
'/') {
359 return matchGlob(next_index, end, str.substr(1));
361 return glob_match_result_t::No;
364 case glob_token_type_t::AnyCharacter:
365 if (str.front() !=
'/') {
366 return matchGlob(next_index, end, str.substr(1));
368 return glob_match_result_t::No;
371 case glob_token_type_t::AnyString:
374 MATCH_GLOB_RECURSE(result, next_index, end, str.substr(i));
377 if (i < str.size() && str[i] ==
'/') {
383 case glob_token_type_t::AnyDirectory:
387 if (i == str.size() || str[i] ==
'/') {
388 MATCH_GLOB_RECURSE(result, next_index, end, str.substr(i));
393 default: hi_no_default();
395#undef MATCH_GLOB_RECURSE
398inline glob_match_result_t matchGlob(glob_token_list_t
const &glob, std::string_view str)
400 return matchGlob(glob.begin(), glob.end(), str);
403inline glob_match_result_t matchGlob(std::string_view glob, std::string_view str)
405 return matchGlob(parseGlob(glob), str);
408inline std::string basePathOfGlob(glob_token_const_iterator first, glob_token_const_iterator last)
416 return x.type == glob_token_type_t::String || x.type == glob_token_type_t::Separator;
419 if (endOfBase != last) {
423 endOfBase = rfind_if(first, endOfBase, [](
hilet &x) {
424 return x.type == glob_token_type_t::Separator;
429 if (endOfBase == first && first->type == glob_token_type_t::Separator) {
434 for (
auto index = first; index != endOfBase; index++) {
435 switch (index->type) {
436 case glob_token_type_t::String: r += index->value;
break;
437 case glob_token_type_t::Separator: r +=
'/';
break;
438 default: hi_no_default();
444inline std::string basePathOfGlob(glob_token_list_t
const &glob)
446 return basePathOfGlob(glob.begin(), glob.end());
449inline std::string basePathOfGlob(std::string_view glob)
451 return basePathOfGlob(parseGlob(glob));
This file includes required definitions.
#define hilet
Invariant should be the default for variables.
Definition required.hpp:23