From: Michael Tremer Date: Sat, 4 Jan 2025 14:14:02 +0000 (+0000) Subject: filelist: Implement binary search for paths X-Git-Tag: 0.9.30~540 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=73f23b5f0b22109bea1523c235125d6517d1bb34;p=pakfire.git filelist: Implement binary search for paths This is a fast path if we are looking for an exact match which will be a lot faster than the linear pattern matching search. Signed-off-by: Michael Tremer --- diff --git a/src/pakfire/filelist.c b/src/pakfire/filelist.c index 552023fe5..dfc2a12c2 100644 --- a/src/pakfire/filelist.c +++ b/src/pakfire/filelist.c @@ -431,10 +431,47 @@ ERROR: return r; } -int pakfire_filelist_contains(struct pakfire_filelist* list, const char* pattern) { - if (!pattern) - return -EINVAL; +static int pakfire_filelist_contains_path( + struct pakfire_filelist* list, const char* path) { + const char* p = NULL; + int i; + int r; + + // Set starting points + int lo = 0; + int hi = list->num_files - 1; + while (lo <= hi) { + // Find the middle + i = lo + (hi - lo) / 2; + + // Fetch the package path + p = pakfire_file_get_path(list->files[i]); + if (!p) + return -EINVAL; + + // Compare the paths + r = strcmp(p, path); + + // We found a match + if (r == 0) + return 1; + + // Search the right half + else if (r < 0) + lo = i + 1; + + // Search the left half + else if (r > 0) + hi = i - 1; + } + + // No match + return 0; +} + +static int pakfire_filelist_contains_pattern( + struct pakfire_filelist* list, const char* pattern) { for (unsigned int i = 0; i < list->num_files; i++) { const char* path = pakfire_file_get_path(list->files[i]); if (!path) @@ -447,6 +484,18 @@ int pakfire_filelist_contains(struct pakfire_filelist* list, const char* pattern return 0; } +int pakfire_filelist_contains(struct pakfire_filelist* list, const char* pattern) { + if (!pattern) + return -EINVAL; + + // If this is a pattern, we perform a naive search + if (pakfire_path_is_pattern(pattern)) + return pakfire_filelist_contains_pattern(list, pattern); + + // Otherwise we perform a binary search to be faster + return pakfire_filelist_contains_path(list, pattern); +} + int pakfire_filelist_walk(struct pakfire_filelist* list, pakfire_filelist_walk_callback callback, void* data, int flags, const char* title) { struct pakfire_progress* progress = NULL; diff --git a/src/pakfire/path.c b/src/pakfire/path.c index d0123e65c..f90017a85 100644 --- a/src/pakfire/path.c +++ b/src/pakfire/path.c @@ -640,6 +640,25 @@ int pakfire_path_match(const char* p, const char* s) { return 1; } +// Returns true if the path contains patterns (i.e. ? and *) +int pakfire_path_is_pattern(const char* path) { + if (!path) + return -EINVAL; + + for (const char* p = path; *p; p++) { + switch (*p) { + case '*': + case '?': + return 1; + + default: + break; + } + } + + return 0; +} + static int pakfire_path_strip_extension(char* path) { if (!path) return -EINVAL; diff --git a/src/pakfire/path.h b/src/pakfire/path.h index 906824f81..b58e871a7 100644 --- a/src/pakfire/path.h +++ b/src/pakfire/path.h @@ -55,6 +55,7 @@ int pakfire_path_is_absolute(const char* s); int __pakfire_path_absolute(char* buffer, const size_t length, const char* s); int pakfire_path_match(const char* p, const char* s); +int pakfire_path_is_pattern(const char* path); #define pakfire_path_replace_extension(path, extension) \ __pakfire_path_replace_extension(path, sizeof(path), extension)