@@ -18,7 +18,7 @@ class GlobCache
18
18
FilesByMapper = T . type_alias do
19
19
T ::Hash [
20
20
String ,
21
- T ::Array [ MapperDescription ]
21
+ T ::Set [ MapperDescription ]
22
22
]
23
23
end
24
24
@@ -32,6 +32,20 @@ def raw_cache_contents
32
32
@raw_cache_contents
33
33
end
34
34
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
+
35
49
sig { returns ( CacheShape ) }
36
50
def expanded_cache
37
51
@expanded_cache = T . let ( @expanded_cache , T . nilable ( CacheShape ) )
@@ -52,20 +66,45 @@ def expanded_cache
52
66
end
53
67
54
68
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 )
59
73
expanded_cache . each do |mapper_description , file_by_owner |
60
74
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
63
77
end
64
78
end
65
79
66
- files_by_mapper
80
+ files_by_mappers
67
81
end
68
82
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
69
108
end
70
109
end
71
110
end
0 commit comments