Skip to content

Commit b94e61c

Browse files
authored
Turn the search Score into an extension type (#8160)
1 parent 55c2993 commit b94e61c

File tree

5 files changed

+56
-70
lines changed

5 files changed

+56
-70
lines changed

app/lib/search/mem_index.dart

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ class InMemoryPackageIndex {
162162

163163
// filter packages that doesn't match text query
164164
if (textResults != null) {
165-
final keys = textResults.pkgScore.getKeys();
165+
final keys = textResults.pkgScore.keys.toSet();
166166
packages.removeWhere((x) => !keys.contains(x));
167167
}
168168

@@ -179,12 +179,12 @@ class InMemoryPackageIndex {
179179
/// it linearly into the [0.4-1.0] range, to allow better
180180
/// multiplication outcomes.
181181
final overallScore = textResults.pkgScore
182-
.map((key, value) => value * _adjustedOverallScores[key]!);
183-
packageHits = _rankWithValues(overallScore.getValues());
182+
.mapValues((key, value) => value * _adjustedOverallScores[key]!);
183+
packageHits = _rankWithValues(overallScore);
184184
break;
185185
case SearchOrder.text:
186-
final score = textResults?.pkgScore ?? Score.empty();
187-
packageHits = _rankWithValues(score.getValues());
186+
final score = textResults?.pkgScore ?? Score.empty;
187+
packageHits = _rankWithValues(score);
188188
break;
189189
case SearchOrder.created:
190190
packageHits = _createdOrderedHits.whereInSet(packages);
@@ -294,7 +294,7 @@ class InMemoryPackageIndex {
294294
coreScores.add(score);
295295
// don't update if the query is single-word
296296
if (words.length > 1) {
297-
wordScopedPackages = score.getKeys();
297+
wordScopedPackages = score.keys.toSet();
298298
if (wordScopedPackages.isEmpty) {
299299
break;
300300
}
@@ -303,15 +303,15 @@ class InMemoryPackageIndex {
303303

304304
final core = Score.multiply(coreScores);
305305

306-
var symbolPages = Score.empty();
306+
var symbolPages = Score.empty;
307307
if (!checkAborted()) {
308308
symbolPages = _apiSymbolIndex.searchWords(words, weight: 0.70);
309309
}
310310

311311
final apiPackages = <String, double>{};
312312
final topApiPages = <String, List<MapEntry<String, double>>>{};
313313
const maxApiPageCount = 2;
314-
for (final entry in symbolPages.getValues().entries) {
314+
for (final entry in symbolPages.entries) {
315315
final pkg = _apiDocPkg(entry.key);
316316
if (!packages.contains(pkg)) continue;
317317

@@ -344,14 +344,15 @@ class InMemoryPackageIndex {
344344
final phrases = extractExactPhrases(text);
345345
if (!aborted && phrases.isNotEmpty) {
346346
final matched = <String, double>{};
347-
for (final package in score.getKeys()) {
347+
for (final MapEntry(key: package, value: packageScore)
348+
in score.entries) {
348349
final doc = _documentsByName[package]!;
349350
final bool matchedAllPhrases = phrases.every((phrase) =>
350351
doc.package.contains(phrase) ||
351352
doc.description!.contains(phrase) ||
352353
doc.readme!.contains(phrase));
353354
if (matchedAllPhrases) {
354-
matched[package] = score[package];
355+
matched[package] = packageScore;
355356
}
356357
}
357358
score = Score(matched);
@@ -444,7 +445,7 @@ class _TextResults {
444445
final List<String>? nameMatches;
445446

446447
factory _TextResults.empty() => _TextResults(
447-
Score.empty(),
448+
Score.empty,
448449
{},
449450
nameMatches: null,
450451
);

app/lib/search/sdk_mem_index.dart

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ class SdkMemIndex {
141141
final libraryWeight = _libraryWeights[library] ?? 1.0;
142142
final weightedResults = isQualifiedQuery
143143
? plainResults
144-
: plainResults.map(
144+
: plainResults.mapValues(
145145
(key, value) {
146146
final dir = p.dirname(key);
147147
final w = (_apiPageDirWeights[dir] ?? 1.0) * libraryWeight;
@@ -169,9 +169,7 @@ class SdkMemIndex {
169169
description: _descriptionPerLibrary[hit.library],
170170
url: _baseUriPerLibrary[hit.library] ?? _baseUri.toString(),
171171
score: hit.score,
172-
apiPages: hit.top
173-
.getValues()
174-
.entries
172+
apiPages: hit.top.entries
175173
.map(
176174
(e) => ApiPageRef(
177175
path: e.key,

app/lib/search/token_index.dart

Lines changed: 24 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -9,47 +9,40 @@ import 'package:meta/meta.dart';
99
import 'text_utils.dart';
1010

1111
/// Represents an evaluated score as an {id: score} map.
12-
class Score {
13-
final Map<String, double> _values;
12+
extension type const Score._(Map<String, double> _values)
13+
implements Map<String, double> {
14+
static const Score empty = Score._({});
1415

1516
Score(this._values);
16-
Score.empty() : _values = const <String, double>{};
1717

18-
bool get isEmpty => _values.isEmpty;
19-
bool get isNotEmpty => !isEmpty;
18+
factory Score.fromEntries(Iterable<MapEntry<String, double>> entries) =>
19+
Score(Map.fromEntries(entries));
2020

21-
Set<String> getKeys({bool Function(String key)? where}) =>
22-
_values.keys.where((e) => where == null || where(e)).toSet();
23-
late final double maxValue = _values.values.fold(0.0, math.max);
24-
Map<String, double> getValues() => _values;
25-
bool containsKey(String key) => _values.containsKey(key);
26-
int get length => _values.length;
27-
28-
double operator [](String key) => _values[key] ?? 0.0;
21+
double get maxValue => _values.values.fold(0.0, math.max);
2922

3023
/// Calculates the intersection of the [scores], by multiplying the values.
3124
static Score multiply(List<Score> scores) {
3225
if (scores.isEmpty) {
33-
return Score.empty();
26+
return Score.empty;
3427
}
3528
if (scores.length == 1) {
3629
return scores.single;
3730
}
3831
if (scores.any((score) => score.isEmpty)) {
39-
return Score.empty();
32+
return Score.empty;
4033
}
41-
var keys = scores.first.getValues().keys.toSet();
34+
var keys = scores.first.keys.toSet();
4235
for (var i = 1; i < scores.length; i++) {
43-
keys = keys.intersection(scores[i].getValues().keys.toSet());
36+
keys = keys.intersection(scores[i].keys.toSet());
4437
}
4538
if (keys.isEmpty) {
46-
return Score.empty();
39+
return Score.empty;
4740
}
4841
final values = <String, double>{};
4942
for (final key in keys) {
50-
var value = scores.first.getValues()[key]!;
43+
var value = scores.first[key]!;
5144
for (var i = 1; i < scores.length; i++) {
52-
value *= scores[i].getValues()[key]!;
45+
value *= scores[i][key]!;
5346
}
5447
values[key] = value;
5548
}
@@ -63,17 +56,17 @@ class Score {
6356
scores.removeWhere((s) => s.isEmpty);
6457

6558
if (scores.isEmpty) {
66-
return Score.empty();
59+
return Score.empty;
6760
}
6861
if (scores.length == 1) {
6962
return scores.single;
7063
}
71-
final keys = scores.expand((e) => e.getValues().keys).toSet();
64+
final keys = scores.expand((e) => e.keys).toSet();
7265
final result = <String, double>{};
7366
for (final key in keys) {
7467
var value = 0.0;
7568
for (var i = 0; i < scores.length; i++) {
76-
final v = scores[i].getValues()[key];
69+
final v = scores[i][key];
7770
if (v != null) {
7871
value = math.max(value, v);
7972
}
@@ -97,24 +90,18 @@ class Score {
9790
if (threshold == null) {
9891
return this;
9992
}
100-
final result = Map<String, double>.fromEntries(
93+
return Score.fromEntries(
10194
_values.entries.where((entry) => entry.value >= threshold!));
102-
return Score(result);
10395
}
10496

10597
/// Keeps the scores only for values in [keys].
106-
Score project(Set<String> keys) {
107-
final result = Map<String, double>.fromEntries(
108-
_values.entries.where((entry) => keys.contains(entry.key)));
109-
return Score(result);
110-
}
98+
Score project(Set<String> keys) => Score.fromEntries(
99+
_values.entries.where((entry) => keys.contains(entry.key)));
111100

112101
/// Transfer the score values with [f].
113-
Score map(double Function(String key, double value) f) {
114-
final result = Map<String, double>.fromEntries(
115-
_values.entries.map((e) => MapEntry(e.key, f(e.key, e.value))));
116-
return Score(result);
117-
}
102+
Score mapValues(double Function(String key, double value) f) =>
103+
Score.fromEntries(
104+
_values.entries.map((e) => MapEntry(e.key, f(e.key, e.value))));
118105

119106
/// Returns a new [Score] object with the top [count] entry.
120107
Score top(int count, {double? minValue}) {
@@ -276,7 +263,7 @@ class TokenIndex {
276263
Score searchWords(List<String> words,
277264
{double weight = 1.0, Set<String>? limitToIds}) {
278265
if (limitToIds != null && limitToIds.isEmpty) {
279-
return Score.empty();
266+
return Score.empty;
280267
}
281268
final scores = <Score>[];
282269
for (final w in words) {
@@ -288,7 +275,7 @@ class TokenIndex {
288275
limitToIds: limitToIds,
289276
);
290277
if (values.isEmpty) {
291-
return Score.empty();
278+
return Score.empty;
292279
}
293280
scores.add(Score(values));
294281
}

app/test/search/package_name_index_test.dart

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ void main() {
1919

2020
test('fluent vs fluent_ui', () {
2121
expect(
22-
index.search('fluent').getValues(),
22+
index.search('fluent'),
2323
{
2424
'fluent': 1.0,
2525
'fluent_ui': 1.0,
@@ -29,7 +29,7 @@ void main() {
2929

3030
test('get vs get_it', () {
3131
expect(
32-
index.search('get').getValues(),
32+
index.search('get'),
3333
{
3434
'get': 1.0,
3535
'get_it': 1.0,
@@ -38,14 +38,14 @@ void main() {
3838
});
3939

4040
test('get_it', () {
41-
expect(index.search('get_it').getValues(), {
41+
expect(index.search('get_it'), {
4242
'get_it': 1.0,
4343
});
4444
});
4545

4646
test('modular vs modular_flutter', () {
4747
expect(
48-
index.search('modular').getValues(),
48+
index.search('modular'),
4949
{
5050
'modular': 1.0,
5151
'modular_flutter': 1.0,
@@ -55,21 +55,21 @@ void main() {
5555

5656
test('mixed parts: fluent it', () {
5757
expect(
58-
index.search('fluent it').getValues(),
58+
index.search('fluent it'),
5959
{},
6060
);
6161
});
6262

6363
test('mixed parts: fluent flutter', () {
6464
expect(
65-
index.search('fluent flutter').getValues(),
65+
index.search('fluent flutter'),
6666
{},
6767
);
6868
});
6969

7070
test('prefix: f', () {
7171
expect(
72-
index.search('f').getValues(),
72+
index.search('f'),
7373
{
7474
'fluent': 1.0,
7575
'fluent_ui': 1.0,
@@ -80,7 +80,7 @@ void main() {
8080

8181
test('prefix: fl', () {
8282
expect(
83-
index.search('fl').getValues(),
83+
index.search('fl'),
8484
{
8585
'fluent': 1.0,
8686
'fluent_ui': 1.0,
@@ -91,7 +91,7 @@ void main() {
9191

9292
test('prefix: flu', () {
9393
expect(
94-
index.search('flu').getValues(),
94+
index.search('flu'),
9595
{
9696
'fluent': 1.0,
9797
'fluent_ui': 1.0,
@@ -102,21 +102,21 @@ void main() {
102102

103103
test('prefix: fluf', () {
104104
expect(
105-
index.search('fluf').getValues(),
105+
index.search('fluf'),
106106
{'fluent': 0.5, 'fluent_ui': 0.5, 'modular_flutter': 0.5},
107107
);
108108
});
109109

110110
test('prefix: fluff', () {
111111
expect(
112-
index.search('fluff').getValues(),
112+
index.search('fluff'),
113113
{},
114114
);
115115
});
116116

117117
test('prefix: fluffy', () {
118118
expect(
119-
index.search('fluffy').getValues(),
119+
index.search('fluffy'),
120120
{},
121121
);
122122
});

app/test/search/token_index_test.dart

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -113,24 +113,24 @@ void main() {
113113
});
114114

115115
test('remove low scores', () {
116-
expect(score.getValues(), {
116+
expect(score, {
117117
'a': 100.0,
118118
'b': 30.0,
119119
'c': 55.0,
120120
});
121-
expect(score.removeLowValues(fraction: 0.31).getValues(), {
121+
expect(score.removeLowValues(fraction: 0.31), {
122122
'a': 100.0,
123123
'c': 55.0,
124124
});
125-
expect(score.removeLowValues(minValue: 56.0).getValues(), {
125+
expect(score.removeLowValues(minValue: 56.0), {
126126
'a': 100.0,
127127
});
128128
});
129129

130130
test('top', () {
131-
expect(score.top(1).getValues(), {'a': 100.0});
132-
expect(score.top(2).getValues(), {'a': 100.0, 'c': 55.0});
133-
expect(score.top(2, minValue: 60).getValues(), {'a': 100.0});
131+
expect(score.top(1), {'a': 100.0});
132+
expect(score.top(2), {'a': 100.0, 'c': 55.0});
133+
expect(score.top(2, minValue: 60), {'a': 100.0});
134134
});
135135
});
136136
}

0 commit comments

Comments
 (0)