@@ -28,7 +28,10 @@ class InMemoryPackageIndex {
2828 late final TokenIndex <String > _readmeIndex;
2929 late final TokenIndex <IndexedApiDocPage > _apiSymbolIndex;
3030 late final _scorePool = ScorePool (_packageNameIndex._packageNames);
31- final _tagIds = < String , int > {};
31+
32+ /// Maps the tag strings to a list of document index values
33+ /// (`PackageDocument doc.tags -> List<_documents.indexOf(doc)>` ).
34+ final _tagDocumentIndices = < String , List <int >> {};
3235 final _documentTagIds = < List <int >> [];
3336
3437 /// Adjusted score takes the overall score and transforms
@@ -63,7 +66,7 @@ class InMemoryPackageIndex {
6366 // transform tags into numberical IDs
6467 final tagIds = < int > [];
6568 for (final tag in doc.tags) {
66- tagIds. add (_tagIds. putIfAbsent (tag, () => _tagIds.length) );
69+ _tagDocumentIndices. putIfAbsent (tag, () => []). add (i );
6770 }
6871 tagIds.sort ();
6972 _documentTagIds.add (tagIds);
@@ -134,11 +137,7 @@ class InMemoryPackageIndex {
134137 PackageSearchResult search (ServiceSearchQuery query) {
135138 // prevent any work if offset is outside of the range
136139 if ((query.offset ?? 0 ) > _documents.length) {
137- return PackageSearchResult (
138- timestamp: clock.now (),
139- totalCount: 0 ,
140- packageHits: [],
141- );
140+ return PackageSearchResult .empty ();
142141 }
143142 return _scorePool.withScore (
144143 value: 1.0 ,
@@ -162,49 +161,36 @@ class InMemoryPackageIndex {
162161 final combinedTagsPredicate =
163162 query.tagsPredicate.appendPredicate (query.parsedQuery.tagsPredicate);
164163 if (combinedTagsPredicate.isNotEmpty) {
165- // The list of predicate tag entries, converted to tag IDs (or -1 if there is no indexed tag),
166- // sorted by their id.
167- final entriesToCheck = combinedTagsPredicate.entries
168- .map ((e) => MapEntry (_tagIds[e.key] ?? - 1 , e.value))
169- .toList ()
170- ..sort ((a, b) => a.key.compareTo (b.key));
171-
172- packageScores.retainWhere ((docIndex, _) {
173- // keeping track of tag id iteration with the `nextTagIndex`
174- final tagIds = _documentTagIds[docIndex];
175- var nextTagIndex = 0 ;
176-
177- for (final entry in entriesToCheck) {
178- if (entry.key == - 1 ) {
179- // no tag id is present for this predicate
180- if (entry.value) {
181- // the predicate is required, no document will match it
182- return false ;
183- } else {
184- // the predicate is prohibited, no document has it, always a match
164+ for (final entry in combinedTagsPredicate.entries) {
165+ final docIndexes = _tagDocumentIndices[entry.key];
166+
167+ if (entry.value) {
168+ // predicate is required, zeroing the gaps between index values
169+ if (docIndexes == null ) {
170+ // the predicate is required, no document will match it
171+ return PackageSearchResult .empty ();
172+ }
173+
174+ for (var i = 0 ; i < docIndexes.length; i++ ) {
175+ if (i == 0 ) {
176+ packageScores.fillRange (0 , docIndexes[i], 0.0 );
185177 continue ;
186178 }
179+ packageScores.fillRange (docIndexes[i - 1 ] + 1 , docIndexes[i], 0.0 );
187180 }
181+ packageScores.fillRange (docIndexes.last + 1 , _documents.length, 0.0 );
182+ } else {
183+ // predicate is prohibited, zeroing the values
188184
189- // skipping the present tag ids until the currently matched predicate tag id
190- while (nextTagIndex < tagIds.length &&
191- tagIds[nextTagIndex] < entry.key) {
192- nextTagIndex++ ;
185+ if (docIndexes == null ) {
186+ // the predicate is prohibited, no document has it, always a match
187+ continue ;
193188 }
194-
195- // checking presence
196- late bool present;
197- if (nextTagIndex == tagIds.length) {
198- present = false ;
199- } else {
200- present = tagIds[nextTagIndex] == entry.key;
189+ for (final i in docIndexes) {
190+ packageScores.setValue (i, 0.0 );
201191 }
202-
203- if (entry.value && ! present) return false ;
204- if (! entry.value && present) return false ;
205192 }
206- return true ;
207- });
193+ }
208194 }
209195
210196 // filter on dependency
0 commit comments