HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
glob.hpp
Go to the documentation of this file.
1// Copyright Take Vos 2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "path_location.hpp"
8#include "../char_maps/module.hpp"
9#include "../utility/utility.hpp"
10#include "../macros.hpp"
11#include <vector>
12#include <string>
13#include <string_view>
14#include <filesystem>
15#include <variant>
16#include <type_traits>
17
21hi_export_module(hikogui.path.glob);
22
23hi_export namespace hi { inline namespace v1 {
24
44public:
45 constexpr glob_pattern() noexcept = default;
46 constexpr glob_pattern(glob_pattern const&) noexcept = default;
47 constexpr glob_pattern(glob_pattern&&) noexcept = default;
48 constexpr glob_pattern& operator=(glob_pattern const&) noexcept = default;
49 constexpr glob_pattern& operator=(glob_pattern&&) noexcept = default;
50
55 constexpr glob_pattern(std::u32string_view str) : _tokens(parse(str)) {}
56
61 constexpr glob_pattern(std::u32string const& str) : glob_pattern(std::u32string_view{str}) {}
62
67 constexpr glob_pattern(char32_t const *str) : glob_pattern(std::u32string_view{str}) {}
68
73 constexpr glob_pattern(std::string_view str) : glob_pattern(hi::to_u32string(str)) {}
74
79 constexpr glob_pattern(std::string const& str) : glob_pattern(std::string_view{str}) {}
80
86 constexpr glob_pattern(char const *str) : glob_pattern(std::string_view{str}) {}
87
92 glob_pattern(std::filesystem::path const& path) : glob_pattern(path.generic_u32string()) {}
93
99 {
100 auto r = std::u32string{};
101 for (hilet& token : _tokens) {
102 r += token.u32string();
103 }
104 return r;
105 }
106
112 {
113 return hi::to_string(u32string());
114 }
115
123 {
124 auto r = std::u32string{};
125 for (hilet& token : _tokens) {
126 r += token.debug_u32string();
127 }
128 return r;
129 }
130
138 {
139 return hi::to_string(debug_u32string());
140 }
141
154 {
155 if (_tokens.empty() or not _tokens.front().is_text()) {
156 return {};
157 } else {
158 auto r = _tokens.front().u32string();
159 if (_tokens.size() >= 2 and _tokens[1].is_any_directory()) {
160 // An any_directory_type always includes at least 1 slash.
161 r += U'/';
162 }
163 return r;
164 }
165 }
166
179 {
180 return to_string(base_u32string());
181 }
182
193 [[nodiscard]] std::filesystem::path base_path() const noexcept
194 {
195 auto text = base_u32string();
196 if (auto i = text.rfind('/'); i == std::u32string::npos) {
197 // If there is no slash then there is no base directory.
198 text.clear();
199 } else {
200 // Include the trailing slash of the base directory.
201 text.resize(i + 1);
202 }
203 auto path = std::filesystem::path{std::move(text)};
204 path.make_preferred(); // returns a reference to *this.
205 return path;
206 }
207
213 [[nodiscard]] constexpr bool matches(std::u32string_view str) const noexcept
214 {
215 auto first = _tokens.cbegin();
216 auto last = _tokens.cend();
217
218 // Strip away the prefix and suffix quickly.
219 if (not matches_strip(first, last, str)) {
220 // The prefix and suffix of the do not match.
221 return false;
222
223 } else if (first == last) {
224 // All tokens matched the prefix and suffix.
225 // If the resulting string is empty than it is a match.
226 return str.empty();
227 }
228
229 // Do more complex matching with the stripped string.
230 return matches(first, last, str);
231 }
232
238 [[nodiscard]] constexpr bool matches(std::u32string const& str) const noexcept
239 {
240 return matches(std::u32string_view{str});
241 }
242
248 [[nodiscard]] constexpr bool matches(char32_t const *str) const noexcept
249 {
250 return matches(std::u32string_view{str});
251 }
252
258 [[nodiscard]] constexpr bool matches(std::string_view str) const noexcept
259 {
260 return matches(to_u32string(str));
261 }
262
268 [[nodiscard]] constexpr bool matches(std::string const& str) const noexcept
269 {
270 return matches(std::string_view{str});
271 }
272
278 [[nodiscard]] constexpr bool matches(char const *str) const noexcept
279 {
280 return matches(std::string_view{str});
281 }
282
288 [[nodiscard]] bool matches(std::filesystem::path const& path) const noexcept
289 {
290 return matches(path.generic_u32string());
291 }
292
293private:
294 enum class match_result_type { fail, success, unchecked };
295
296 class token_type {
297 public:
298 using text_type = std::u32string;
299 using character_class_type = std::vector<std::pair<char32_t, char32_t>>;
300 using alternation_type = std::vector<std::u32string>;
304
305 constexpr token_type(token_type const&) noexcept = default;
306 constexpr token_type(token_type&&) noexcept = default;
307 constexpr token_type& operator=(token_type const&) noexcept = default;
308 constexpr token_type& operator=(token_type&&) noexcept = default;
309
310 constexpr token_type(text_type&& rhs) noexcept : _value(std::move(rhs)) {}
311 constexpr token_type(character_class_type&& rhs) noexcept : _value(std::move(rhs)) {}
312 constexpr token_type(alternation_type&& rhs) noexcept : _value(std::move(rhs)) {}
313 constexpr token_type(any_character_type&& rhs) noexcept : _value(std::move(rhs)) {}
314 constexpr token_type(any_text_type&& rhs) noexcept : _value(std::move(rhs)) {}
315 constexpr token_type(any_directory_type&& rhs) noexcept : _value(std::move(rhs)) {}
316
317 [[nodiscard]] constexpr bool is_text() const noexcept
318 {
319 return std::holds_alternative<text_type>(_value);
320 }
321
322 [[nodiscard]] constexpr bool is_any_directory() const noexcept
323 {
324 return std::holds_alternative<any_directory_type>(_value);
325 }
326
327 template<bool Left>
328 [[nodiscard]] constexpr match_result_type strip(std::u32string_view& str) const noexcept
329 {
330 constexpr bool Right = not Left;
331
332 if (hilet text_ptr = std::get_if<text_type>(&_value)) {
333 if (Left and str.starts_with(*text_ptr)) {
334 str.remove_prefix(text_ptr->size());
335 return match_result_type::success;
336
337 } else if (Right and str.ends_with(*text_ptr)) {
338 str.remove_suffix(text_ptr->size());
339 return match_result_type::success;
340
341 } else {
342 return match_result_type::fail;
343 }
344
345 } else if (hilet character_class_ptr = std::get_if<character_class_type>(&_value)) {
346 if (str.empty()) {
347 return match_result_type::fail;
348 }
349 hilet c = Left ? str.front() : str.back();
350 for (hilet[first_char, last_char] : *character_class_ptr) {
351 if (c >= first_char and c <= last_char) {
352 if constexpr (Left) {
353 str.remove_prefix(1);
354 } else {
355 str.remove_suffix(1);
356 }
357 return match_result_type::success;
358 }
359 }
360 return match_result_type::fail;
361
362 } else if (std::holds_alternative<any_character_type>(_value)) {
363 if (str.empty()) {
364 return match_result_type::fail;
365 }
366 if constexpr (Left) {
367 str.remove_prefix(1);
368 } else {
369 str.remove_suffix(1);
370 }
371 return match_result_type::success;
372
373 } else {
374 return match_result_type::unchecked;
375 }
376 }
377
378 [[nodiscard]] constexpr match_result_type matches(std::u32string_view& str, size_t iteration) const noexcept
379 {
380 if (hilet text_ptr = std::get_if<text_type>(&_value)) {
381 if (iteration != 0) {
382 return match_result_type::fail;
383
384 } else if (str.starts_with(*text_ptr)) {
385 str.remove_prefix(text_ptr->size());
386 return match_result_type::success;
387
388 } else {
389 return match_result_type::fail;
390 }
391
392 } else if (hilet character_class_ptr = std::get_if<character_class_type>(&_value)) {
393 if (iteration != 0 or str.empty()) {
394 return match_result_type::fail;
395 } else {
396 hilet c = str.front();
397 for (hilet[first_char, last_char] : *character_class_ptr) {
398 if (c >= first_char and c <= last_char) {
399 str.remove_prefix(1);
400 return match_result_type::success;
401 }
402 }
403 return match_result_type::fail;
404 }
405
406 } else if (hilet alternation_ptr = std::get_if<alternation_type>(&_value)) {
407 if (iteration >= alternation_ptr->size()) {
408 return match_result_type::fail;
409 } else if (str.starts_with((*alternation_ptr)[iteration])) {
410 str.remove_prefix((*alternation_ptr)[iteration].size());
411 return match_result_type::success;
412 } else {
413 return match_result_type::unchecked;
414 }
415
416 } else if (std::holds_alternative<any_character_type>(_value)) {
417 if (iteration != 0 or str.empty()) {
418 return match_result_type::fail;
419 } else {
420 str.remove_prefix(1);
421 return match_result_type::success;
422 }
423
424 } else if (std::holds_alternative<any_text_type>(_value)) {
425 if (iteration > str.size() or iteration > str.find('/')) {
426 return match_result_type::fail;
427 } else {
428 str.remove_prefix(iteration);
429 return match_result_type::success;
430 }
431
432 } else if (std::holds_alternative<any_directory_type>(_value)) {
433 if (str.empty() or str.front() != '/') {
434 return match_result_type::fail;
435 } else {
436 for (auto i = 0_uz; i != std::u32string_view::npos; i = str.find('/', i + 1)) {
437 if (iteration-- == 0) {
438 str.remove_prefix(i + 1);
439 return match_result_type::success;
440 }
441 }
442 return match_result_type::fail;
443 }
444
445 } else {
446 hi_no_default();
447 }
448 }
449
450 [[nodiscard]] constexpr std::u32string u32string() const noexcept
451 {
452 auto r = std::u32string{};
453
454 if (auto text_ptr = std::get_if<text_type>(&_value)) {
455 r = *text_ptr;
456
457 } else if (auto character_class_ptr = std::get_if<character_class_type>(&_value)) {
458 r += U'[';
459 for (hilet[first_char, last_char] : *character_class_ptr) {
460 if (first_char == last_char) {
461 r += first_char;
462 } else {
463 r += first_char;
464 r += U'-';
465 r += last_char;
466 }
467 }
468 r += U']';
469
470 } else if (auto alternation_ptr = std::get_if<alternation_type>(&_value)) {
471 r += U'{';
472 for (hilet& text : *alternation_ptr) {
473 if (r.size() > 1) {
474 r += U',';
475 }
476 r += text;
477 }
478 r += U'}';
479
480 } else if (std::holds_alternative<any_character_type>(_value)) {
481 r += U'?';
482
483 } else if (std::holds_alternative<any_text_type>(_value)) {
484 r += U'*';
485
486 } else if (std::holds_alternative<any_directory_type>(_value)) {
487 r += U"/**/";
488
489 } else {
490 hi_no_default();
491 }
492
493 return r;
494 }
495
496 [[nodiscard]] constexpr std::u32string debug_u32string() const noexcept
497 {
498 auto r = std::u32string{};
499
500 if (auto text_ptr = std::get_if<text_type>(&_value)) {
501 r += U'\'';
502 r += *text_ptr;
503 r += U'\'';
504
505 } else if (auto character_class_ptr = std::get_if<character_class_type>(&_value)) {
506 r += U'[';
507 for (hilet[first_char, last_char] : *character_class_ptr) {
508 if (first_char == last_char) {
509 r += first_char;
510 } else {
511 r += first_char;
512 r += U'-';
513 r += last_char;
514 }
515 }
516 r += U']';
517
518 } else if (auto alternation_ptr = std::get_if<alternation_type>(&_value)) {
519 r += U'{';
520 for (hilet& text : *alternation_ptr) {
521 if (r.size() > 1) {
522 r += U',';
523 }
524 r += text;
525 }
526 r += U'}';
527
528 } else if (std::holds_alternative<any_character_type>(_value)) {
529 r += U'?';
530
531 } else if (std::holds_alternative<any_text_type>(_value)) {
532 r += U'*';
533
534 } else if (std::holds_alternative<any_directory_type>(_value)) {
535 r += U"/**/";
536
537 } else {
538 hi_no_default();
539 }
540
541 return r;
542 }
543
544 private:
545 using variant_type = std::
546 variant<text_type, character_class_type, alternation_type, any_character_type, any_text_type, any_directory_type>;
547
548 variant_type _value;
549 };
550
551 using tokens_type = std::vector<token_type>;
552 using const_iterator = tokens_type::const_iterator;
553
554 tokens_type _tokens;
555
556 [[nodiscard]] constexpr static token_type make_text(token_type::text_type&& rhs) noexcept
557 {
558 return token_type{std::move(rhs)};
559 }
560
561 [[nodiscard]] constexpr static token_type make_alternation(token_type::alternation_type&& rhs) noexcept
562 {
563 return token_type{std::move(rhs)};
564 }
565
566 [[nodiscard]] constexpr static token_type make_character_class(token_type::character_class_type&& rhs) noexcept
567 {
568 return token_type{std::move(rhs)};
569 }
570
571 [[nodiscard]] constexpr static token_type make_any_character() noexcept
572 {
573 return token_type{token_type::any_character_type{}};
574 }
575
576 [[nodiscard]] constexpr static token_type make_any_text() noexcept
577 {
578 return token_type{token_type::any_text_type{}};
579 }
580
581 [[nodiscard]] constexpr static token_type make_any_directory() noexcept
582 {
583 return token_type{token_type::any_directory_type{}};
584 }
585
586 [[nodiscard]] constexpr static tokens_type parse(auto first, auto last)
587 {
588#define HI_GLOB_APPEND_TEXT() \
589 do { \
590 if (not text.empty()) { \
591 r.emplace_back(make_text(std::move(text))); \
592 text.clear(); \
593 } \
594 } while (false)
595
596 enum class state_type { idle, star, slash, slash_star, slash_star_star, bracket, bracket_range, brace };
597 using enum state_type;
598
599 static_assert(std::is_same_v<std::decay_t<decltype(*first)>, char32_t>);
600
601 auto r = tokens_type{};
602
603 auto state = idle;
604 auto text = token_type::text_type{};
605 auto alternation = token_type::alternation_type{};
606 auto character_class = token_type::character_class_type{};
607
608 auto it = first;
609 while (it != last) {
610 auto c = *it;
611 switch (state) {
612 case idle:
613 switch (c) {
614 case U'/':
615 state = slash;
616 break;
617 case U'?':
618 HI_GLOB_APPEND_TEXT();
619 r.push_back(make_any_character());
620 break;
621 case U'*':
622 state = star;
623 break;
624 case U'[':
625 HI_GLOB_APPEND_TEXT();
626 state = bracket;
627 break;
628 case U'{':
629 HI_GLOB_APPEND_TEXT();
630 state = brace;
631 break;
632 default:
633 text += c;
634 }
635 break;
636
637 case star:
638 if (c == U'*') {
639 throw parse_error("Double ** is only allowed between slashes, like /**/.");
640 } else {
641 HI_GLOB_APPEND_TEXT();
642 r.push_back(make_any_text());
643 text += c;
644 state = idle;
645 }
646 break;
647
648 case slash:
649 if (c == U'*') {
650 state = slash_star;
651 } else {
652 text += U'/';
653 text += c;
654 state = idle;
655 }
656 break;
657
658 case slash_star:
659 if (c == U'*') {
660 state = slash_star_star;
661 } else {
662 text += U'/';
663 HI_GLOB_APPEND_TEXT();
664 r.push_back(make_any_text());
665 text += c;
666 state = idle;
667 }
668 break;
669
670 case slash_star_star:
671 if (c == U'/') {
672 HI_GLOB_APPEND_TEXT();
673 r.push_back(make_any_directory());
674 state = idle;
675 } else {
676 throw parse_error("Double ** is only allowed between slashes, like /**/.");
677 }
678 break;
679
680 case bracket:
681 if (c == U'-') {
682 if (character_class.empty()) {
683 character_class.emplace_back(c, c);
684 } else {
685 state = bracket_range;
686 }
687 } else if (c == U']') {
688 r.push_back(make_character_class(std::move(character_class)));
689 character_class.clear();
690 state = idle;
691 } else {
692 character_class.emplace_back(c, c);
693 }
694 break;
695
696 case bracket_range:
697 if (c == U'-') {
698 throw parse_error("Double '--' is not allowed inside a character class, i.e. between '[' and ']'.");
699 } else if (c == U']') {
700 character_class.emplace_back(U'-', U'-');
701 r.push_back(make_character_class(std::move(character_class)));
702 character_class.clear();
703 state = idle;
704 } else {
705 character_class.back().second = c;
706 state = bracket;
707 }
708 break;
709
710 case brace:
711 if (c == U'}') {
712 if (not text.empty()) {
713 alternation.push_back(std::move(text));
714 text.clear();
715 }
716 r.push_back(make_alternation(std::move(alternation)));
717 alternation.clear();
718 state = idle;
719 } else if (c == U',') {
720 alternation.push_back(std::move(text));
721 text.clear();
722 } else {
723 text += c;
724 }
725 break;
726
727 default:
728 hi_no_default();
729 }
730
731 ++it;
732 }
733
734 switch (state) {
735 case idle:
736 HI_GLOB_APPEND_TEXT();
737 break;
738
739 case star:
740 HI_GLOB_APPEND_TEXT();
741 r.push_back(make_any_text());
742 break;
743
744 case slash:
745 text += U'/';
746 HI_GLOB_APPEND_TEXT();
747 break;
748
749 case slash_star:
750 text += U'/';
751 HI_GLOB_APPEND_TEXT();
752 r.push_back(make_any_text());
753 break;
754
755 case slash_star_star:
756 HI_GLOB_APPEND_TEXT();
757 r.push_back(make_any_directory());
758 break;
759
760 case bracket:
761 throw parse_error("Unclosed bracket '[' found in glob pattern.");
762
763 case bracket_range:
764 throw parse_error("Unclosed bracket '[' found in glob pattern.");
765
766 case brace:
767 throw parse_error("Unclosed brace '{' found in glob pattern.");
768 }
769
770 return r;
771
772#undef HI_GLOB_APPEND_TEXT
773 }
774
775 [[nodiscard]] constexpr static tokens_type parse(auto&& range)
776 {
777 return parse(std::ranges::begin(range), std::ranges::end(range));
778 }
779
780 template<bool Left>
781 [[nodiscard]] constexpr static bool
782 matches_strip(const_iterator& first, const_iterator & last, std::u32string_view& str) noexcept
783 {
784 while (first != last) {
785 hilet it = Left ? first : last - 1;
786 switch (it->strip<Left>(str)) {
787 case match_result_type::fail:
788 return false;
789 case match_result_type::unchecked:
790 return true;
791 case match_result_type::success:
792 if constexpr (Left) {
793 ++first;
794 } else {
795 --last;
796 }
797 break;
798 default:
799 hi_no_default();
800 }
801 }
802 return str.empty();
803 }
804
805 [[nodiscard]] constexpr static bool
806 matches_strip(const_iterator& first, const_iterator& last, std::u32string_view& str) noexcept
807 {
808 return matches_strip<true>(first, last, str) and matches_strip<false>(first, last, str);
809 }
810
811 [[nodiscard]] constexpr bool matches(const_iterator it, const_iterator last, std::u32string_view original) const noexcept
812 {
813 hi_assert(it != last);
814
815 struct stack_element {
816 std::u32string_view str;
817 size_t iteration;
818 };
819
820 auto stack = std::vector<stack_element>{};
821 stack.reserve(std::distance(it, last));
822
823 stack.emplace_back(original, 0);
824 while (true) {
825 auto [str, iteration] = stack.back();
826
827 switch (it->matches(str, iteration)) {
828 case match_result_type::success:
829 if (it + 1 == last) {
830 if (str.empty()) {
831 // This token fully matches the whole string.
832 return true;
833
834 } else {
835 // This token matches, but this is the last token.
836 // Try the next iteration on this token.
837 ++stack.back().iteration;
838 }
839
840 } else {
841 // This token matches, test the next token.
842 stack.emplace_back(str, 0);
843 ++it;
844 }
845 break;
846
847 case match_result_type::unchecked:
848 // This iteration of the token did not match, try the next iteration.
849 ++stack.back().iteration;
850 break;
851
852 case match_result_type::fail:
853 // None of the token iterations succeeded.
854 if (stack.size() == 1) {
855 // Can't track further back; the complete match failed.
856 return false;
857
858 } else {
859 // Track back and try the next iteration of the previous token.
860 stack.pop_back();
861 ++stack.back().iteration;
862 --it;
863 }
864 break;
865
866 default:
867 hi_no_default();
868 }
869 }
870 }
871};
872
880{
881 auto path = pattern.base_path();
882
883 hilet first = std::filesystem::recursive_directory_iterator(path);
884 hilet last = std::filesystem::recursive_directory_iterator();
885 for (auto it = first; it != last; ++it) {
886 hilet& iterated_path = it->path();
887 if (pattern.matches(iterated_path)) {
888 co_yield iterated_path;
889 }
890 }
891}
892
899[[nodiscard]] inline generator<std::filesystem::path> glob(std::string_view pattern)
900{
901 return glob(glob_pattern{std::move(pattern)});
902}
903
911{
912 return glob(glob_pattern{std::move(pattern)});
913}
914
921[[nodiscard]] inline generator<std::filesystem::path> glob(char const *pattern)
922{
923 return glob(glob_pattern{pattern});
924}
925
932[[nodiscard]] inline generator<std::filesystem::path> glob(std::filesystem::path pattern)
933{
934 return glob(glob_pattern{std::move(pattern)});
935}
936
944[[nodiscard]] inline generator<std::filesystem::path> glob(path_location location, std::filesystem::path ref)
945{
946 for (hilet& directory : get_paths(location)) {
947 for (hilet& path : glob(directory / ref)) {
948 co_yield path;
949 }
950 }
951}
952
960[[nodiscard]] inline generator<std::filesystem::path> glob(path_location location, std::string_view ref)
961{
962 return glob(location, std::filesystem::path{std::move(ref)});
963}
964
973{
974 return glob(location, std::filesystem::path{std::move(ref)});
975}
976
985{
986 return glob(location, std::filesystem::path{ref});
987}
988
989}} // namespace hi::v1
functions to locate files and directories.
constexpr std::u32string to_u32string(std::u32string_view rhs) noexcept
Identity conversion from UTF-32 to UTF-32.
Definition to_string.hpp:24
path_location
File and Directory locations.
Definition path_location_intf.hpp:24
generator< std::filesystem::path > glob(glob_pattern pattern)
Find paths on the filesystem that match the glob pattern.
Definition glob.hpp:879
generator< std::filesystem::path > get_paths(path_location location)
Get a set of paths.
STL namespace.
DOXYGEN BUG.
Definition algorithm.hpp:16
geometry/margins.hpp
Definition lookahead_iterator.hpp:5
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:377
Definition token.hpp:15
A glob pattern.
Definition glob.hpp:43
constexpr bool matches(std::string const &str) const noexcept
Match the pattern with the given string.
Definition glob.hpp:268
constexpr std::u32string base_u32string() const noexcept
Get the initial fixed part of the pattern.
Definition glob.hpp:153
constexpr std::string debug_string() noexcept
Convert a glob-pattern to a debug-string.
Definition glob.hpp:137
constexpr glob_pattern(std::u32string const &str)
Parse a string to a glob-pattern.
Definition glob.hpp:61
constexpr std::u32string u32string() noexcept
Convert a glob-pattern to a string.
Definition glob.hpp:98
constexpr glob_pattern(char32_t const *str)
Parse a string to a glob-pattern.
Definition glob.hpp:67
constexpr std::u32string debug_u32string() noexcept
Convert a glob-pattern to a debug-string.
Definition glob.hpp:122
constexpr bool matches(std::u32string const &str) const noexcept
Match the pattern with the given string.
Definition glob.hpp:238
constexpr bool matches(char32_t const *str) const noexcept
Match the pattern with the given string.
Definition glob.hpp:248
constexpr glob_pattern(std::u32string_view str)
Parse a string to a glob-pattern.
Definition glob.hpp:55
constexpr glob_pattern(char const *str)
Parse a string to a glob-pattern.
Definition glob.hpp:86
constexpr std::string base_string() const noexcept
Get the initial fixed part of the pattern.
Definition glob.hpp:178
constexpr bool matches(std::u32string_view str) const noexcept
Match the pattern with the given string.
Definition glob.hpp:213
glob_pattern(std::filesystem::path const &path)
Parse a path to a glob-pattern.
Definition glob.hpp:92
constexpr glob_pattern(std::string const &str)
Parse a string to a glob-pattern.
Definition glob.hpp:79
std::filesystem::path base_path() const noexcept
Get the initial path of the pattern.
Definition glob.hpp:193
bool matches(std::filesystem::path const &path) const noexcept
Match the pattern with the given path.
Definition glob.hpp:288
constexpr glob_pattern(std::string_view str)
Parse a string to a glob-pattern.
Definition glob.hpp:73
constexpr bool matches(std::string_view str) const noexcept
Match the pattern with the given string.
Definition glob.hpp:258
constexpr std::string string() noexcept
Convert a glob-pattern to a string.
Definition glob.hpp:111
constexpr bool matches(char const *str) const noexcept
Match the pattern with the given string.
Definition glob.hpp:278
T cbegin(T... args)
T distance(T... args)
T empty(T... args)
T cend(T... args)
T front(T... args)
T move(T... args)
T reserve(T... args)
T size(T... args)