@@ -18,7 +18,7 @@ class GlobCache
1818 FilesByMapper = T . type_alias do
1919 T ::Hash [
2020 String ,
21- T ::Array [ MapperDescription ]
21+ T ::Set [ MapperDescription ]
2222 ]
2323 end
2424
@@ -32,6 +32,20 @@ def raw_cache_contents
3232 @raw_cache_contents
3333 end
3434
35+ sig { params ( files : T ::Array [ String ] ) . returns ( FilesByMapper ) }
36+ def mapper_descriptions_that_map_files ( files )
37+ if files . count > 100
38+ # When looking at many files, expanding the cache out using Dir.glob and checking for intersections is faster
39+ files_by_mappers = files . map { |f | [ f , Set . new ( [ ] ) ] } . to_h
40+ files_by_mappers . merge ( files_by_mappers_via_expanded_cache )
41+ else
42+ # When looking at few files, using File.fnmatch is faster
43+ files_by_mappers_via_file_fnmatch ( files )
44+ end
45+ end
46+
47+ private
48+
3549 sig { returns ( CacheShape ) }
3650 def expanded_cache
3751 @expanded_cache = T . let ( @expanded_cache , T . nilable ( CacheShape ) )
@@ -52,20 +66,45 @@ def expanded_cache
5266 end
5367
5468 sig { returns ( FilesByMapper ) }
55- def files_by_mapper
56- @files_by_mapper ||= T . let ( @files_by_mapper , T . nilable ( FilesByMapper ) )
57- @files_by_mapper ||= begin
58- files_by_mapper = { }
69+ def files_by_mappers_via_expanded_cache
70+ @files_by_mappers ||= T . let ( @files_by_mappers , T . nilable ( FilesByMapper ) )
71+ @files_by_mappers ||= begin
72+ files_by_mappers = T . let ( { } , FilesByMapper )
5973 expanded_cache . each do |mapper_description , file_by_owner |
6074 file_by_owner . each do |file , owner |
61- files_by_mapper [ file ] ||= [ ]
62- files_by_mapper [ file ] << mapper_description
75+ files_by_mappers [ file ] ||= Set . new ( [ ] )
76+ files_by_mappers . fetch ( file ) << mapper_description
6377 end
6478 end
6579
66- files_by_mapper
80+ files_by_mappers
6781 end
6882 end
83+
84+ sig { params ( files : T ::Array [ String ] ) . returns ( FilesByMapper ) }
85+ def files_by_mappers_via_file_fnmatch ( files )
86+ files_by_mappers = T . let ( { } , FilesByMapper )
87+
88+ files . each do |file |
89+ files_by_mappers [ file ] ||= Set . new ( [ ] )
90+ @raw_cache_contents . each do |mapper_description , globs_by_owner |
91+ # As much as I'd like to *not* special case the file annotations mapper, using File.fnmatch? on the thousands of files mapped by the
92+ # file annotations mapper is a lot of unnecessary extra work.
93+ # Therefore we can just check if the file is in the globs directly for file annotations, otherwise use File.fnmatch
94+ if mapper_description == OwnershipMappers ::FileAnnotations ::DESCRIPTION
95+ files_by_mappers . fetch ( file ) << mapper_description if globs_by_owner [ file ]
96+ else
97+ globs_by_owner . each do |glob , owner |
98+ if File . fnmatch? ( glob , file , File ::FNM_PATHNAME | File ::FNM_EXTGLOB )
99+ files_by_mappers . fetch ( file ) << mapper_description
100+ end
101+ end
102+ end
103+ end
104+ end
105+
106+ files_by_mappers
107+ end
69108 end
70109 end
71110end
0 commit comments