Fix analysis issues in benchmarks/ directory

Now that I'm able to open the entire SDK in VSC, I'm fixing some
of the analysis issues in various files (carefully) without changing
their meaning.

In this case, I removed unnecessary imports from benchmarks.
In regexp_benchmark I ignored one warning which likely would
have changed the behavior of the code.

BUG=https://github.com/dart-lang/sdk/issues/52419

Change-Id: I9a195a4e45121313bd9f065f2579a165c3fec05b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/303901
Auto-Submit: Eric Seidel <eric@shorebird.dev>
Reviewed-by: William Hesse <whesse@google.com>
Commit-Queue: William Hesse <whesse@google.com>
This commit is contained in:
Eric Seidel 2023-05-17 09:14:50 +00:00 committed by Commit Queue
parent 987c7a7c35
commit 4c20cedd30
21 changed files with 134 additions and 80 deletions

View file

@ -7,14 +7,14 @@ import 'dart:isolate';
import 'json_benchmark.dart'; import 'json_benchmark.dart';
import 'latency.dart'; import 'latency.dart';
main() async { Future<void> main() async {
// Start GC pressure from helper isolate. // Start GC pressure from helper isolate.
final exitPort = ReceivePort(); final exitPort = ReceivePort();
final exitFuture = exitPort.first; final exitFuture = exitPort.first;
final isolate = await Isolate.spawn(run, null, onExit: exitPort.sendPort); final isolate = await Isolate.spawn(run, null, onExit: exitPort.sendPort);
// Measure event loop latency. // Measure event loop latency.
const tickDuration = const Duration(milliseconds: 1); const tickDuration = Duration(milliseconds: 1);
const numberOfTicks = 8 * 1000; // min 8 seconds. const numberOfTicks = 8 * 1000; // min 8 seconds.
final EventLoopLatencyStats stats = final EventLoopLatencyStats stats =
await measureEventLoopLatency(tickDuration, numberOfTicks); await measureEventLoopLatency(tickDuration, numberOfTicks);

View file

@ -2,8 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a // for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file. // BSD-style license that can be found in the LICENSE file.
import 'dart:math';
import 'dart:convert'; import 'dart:convert';
import 'dart:math';
class JsonRoundTripBenchmark { class JsonRoundTripBenchmark {
void run() { void run() {

View file

@ -9,14 +9,14 @@ import 'dart:isolate';
import 'json_benchmark.dart'; import 'json_benchmark.dart';
import 'latency.dart'; import 'latency.dart';
main() async { Future<void> main() async {
// Start GC pressure from helper isolate. // Start GC pressure from helper isolate.
final exitPort = ReceivePort(); final exitPort = ReceivePort();
final exitFuture = exitPort.first; final exitFuture = exitPort.first;
final isolate = await Isolate.spawn(run, null, onExit: exitPort.sendPort); final isolate = await Isolate.spawn(run, null, onExit: exitPort.sendPort);
// Measure event loop latency. // Measure event loop latency.
const tickDuration = const Duration(milliseconds: 1); const tickDuration = Duration(milliseconds: 1);
const numberOfTicks = 8 * 1000; // min 8 seconds. const numberOfTicks = 8 * 1000; // min 8 seconds.
final EventLoopLatencyStats stats = final EventLoopLatencyStats stats =
await measureEventLoopLatency(tickDuration, numberOfTicks); await measureEventLoopLatency(tickDuration, numberOfTicks);

View file

@ -7,14 +7,14 @@ import 'dart:isolate';
import 'json_benchmark.dart'; import 'json_benchmark.dart';
import 'latency.dart'; import 'latency.dart';
main() async { Future<void> main() async {
// Start GC pressure from helper isolate. // Start GC pressure from helper isolate.
final exitPort = ReceivePort(); final exitPort = ReceivePort();
final exitFuture = exitPort.first; final exitFuture = exitPort.first;
final isolate = await Isolate.spawn(run, null, onExit: exitPort.sendPort); final isolate = await Isolate.spawn(run, null, onExit: exitPort.sendPort);
// Measure event loop latency. // Measure event loop latency.
const tickDuration = const Duration(milliseconds: 1); const tickDuration = Duration(milliseconds: 1);
const numberOfTicks = 8 * 1000; // min 8 seconds. const numberOfTicks = 8 * 1000; // min 8 seconds.
final EventLoopLatencyStats stats = final EventLoopLatencyStats stats =
await measureEventLoopLatency(tickDuration, numberOfTicks); await measureEventLoopLatency(tickDuration, numberOfTicks);

View file

@ -2,8 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a // for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file. // BSD-style license that can be found in the LICENSE file.
import 'dart:math';
import 'dart:convert'; import 'dart:convert';
import 'dart:math';
class JsonRoundTripBenchmark { class JsonRoundTripBenchmark {
void run() { void run() {

View file

@ -4,16 +4,16 @@
import 'dart:isolate'; import 'dart:isolate';
import 'regexp_benchmark.dart';
import 'latency.dart'; import 'latency.dart';
import 'regexp_benchmark.dart';
main() async { Future<void> main() async {
final exitPort = ReceivePort(); final exitPort = ReceivePort();
final exitFuture = exitPort.first; final exitFuture = exitPort.first;
final isolate = await Isolate.spawn(run, null, onExit: exitPort.sendPort); final isolate = await Isolate.spawn(run, null, onExit: exitPort.sendPort);
// Measure event loop latency. // Measure event loop latency.
const tickDuration = const Duration(milliseconds: 1); const tickDuration = Duration(milliseconds: 1);
const numberOfTicks = 8 * 1000; // min 8 seconds. const numberOfTicks = 8 * 1000; // min 8 seconds.
final EventLoopLatencyStats stats = final EventLoopLatencyStats stats =
await measureEventLoopLatency(tickDuration, numberOfTicks); await measureEventLoopLatency(tickDuration, numberOfTicks);

View file

@ -2,12 +2,10 @@
// for details. All rights reserved. Use of this source code is governed by a // for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file. // BSD-style license that can be found in the LICENSE file.
import 'dart:math';
import 'dart:convert';
class RegexpBenchmark { class RegexpBenchmark {
void run() { void run() {
final re = RegExp(r'(x+)*y'); final re = RegExp(r'(x+)*y');
// ignore: prefer_interpolation_to_compose_strings
final s = 'x' * 26 + ''; final s = 'x' * 26 + '';
re.allMatches(s).iterator.moveNext(); re.allMatches(s).iterator.moveNext();
} }

View file

@ -80,11 +80,11 @@ class D<T> {
} }
'''); ''');
final maxCount = instantiateCounts.reduce(((v, e) => max(v, e))); final maxCount = instantiateCounts.reduce(max);
for (int i = 0; i < maxCount; i++) { for (int i = 0; i < maxCount; i++) {
output.write(''' output.write('''
class C${i} {} class C$i {}
'''); ''');
} }
} }

View file

@ -2,12 +2,13 @@
// for details. All rights reserved. Use of this source code is governed by a // for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file. // BSD-style license that can be found in the LICENSE file.
import 'dart:collection';
// Benchmark for https://github.com/dart-lang/sdk/issues/48641. // Benchmark for https://github.com/dart-lang/sdk/issues/48641.
// //
// Measures the average time needed for a lookup in Sets of integers. // Measures the average time needed for a lookup in Sets of integers.
import 'dart:math'; import 'dart:math';
import 'dart:collection';
import 'package:benchmark_harness/benchmark_harness.dart'; import 'package:benchmark_harness/benchmark_harness.dart';
class SetBenchmark extends BenchmarkBase { class SetBenchmark extends BenchmarkBase {
@ -30,13 +31,13 @@ void main() {
final randomList = List<int>.generate(14790, (_) => r.nextInt(1 << 31)); final randomList = List<int>.generate(14790, (_) => r.nextInt(1 << 31));
final benchmarks = [ final benchmarks = [
() => SetBenchmark("IntegerSetLookup.DefaultHashSet", {...list}), () => SetBenchmark('IntegerSetLookup.DefaultHashSet', {...list}),
() => () =>
SetBenchmark("IntegerSetLookup.HashSet", HashSet<int>()..addAll(list)), SetBenchmark('IntegerSetLookup.HashSet', HashSet<int>()..addAll(list)),
() => () =>
SetBenchmark("IntegerSetLookup.DefaultHashSet_Random", {...randomList}), SetBenchmark('IntegerSetLookup.DefaultHashSet_Random', {...randomList}),
() => SetBenchmark( () => SetBenchmark(
"IntegerSetLookup.HashSet_Random", HashSet<int>()..addAll(randomList)), 'IntegerSetLookup.HashSet_Random', HashSet<int>()..addAll(randomList)),
]; ];
for (final benchmark in benchmarks) { for (final benchmark in benchmarks) {
benchmark().report(); benchmark().report();

View file

@ -49,7 +49,7 @@ class SendReceiveHelper {
outbox.send(null); outbox.send(null);
await workerExitedPort.first; await workerExitedPort.first;
workerExitedPort.close(); workerExitedPort.close();
inbox.cancel(); await inbox.cancel();
} }
// Send regexp to worker, get one back, repeat few times. // Send regexp to worker, get one back, repeat few times.
@ -78,7 +78,7 @@ Future<void> isolate(SendPort sendPort) async {
break; break;
} }
// use RegExp to ensure it is compiled // use RegExp to ensure it is compiled
RegExp re = received as RegExp; final RegExp re = received as RegExp;
re.firstMatch('h' * 1000); re.firstMatch('h' * 1000);
// send the RegExp // send the RegExp
sendPort.send(re); sendPort.send(re);

View file

@ -6,13 +6,11 @@
// via exit/send. // via exit/send.
import 'dart:async'; import 'dart:async';
import 'dart:typed_data';
import 'dart:math' as math;
import 'dart:isolate'; import 'dart:isolate';
import 'latency.dart'; import 'latency.dart';
main() async { Future<void> main() async {
final statsFuture = final statsFuture =
measureEventLoopLatency(const Duration(milliseconds: 1), 4000, work: () { measureEventLoopLatency(const Duration(milliseconds: 1), 4000, work: () {
// Every 1 ms we allocate some objects which may trigger GC some time. // Every 1 ms we allocate some objects which may trigger GC some time.

View file

@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file. // BSD-style license that can be found in the LICENSE file.
import 'dart:async'; import 'dart:async';
import 'dart:io';
import 'dart:math' as math; import 'dart:math' as math;
import 'dart:typed_data'; import 'dart:typed_data';

View file

@ -8,10 +8,11 @@ import 'dart:io';
import 'dart:isolate'; import 'dart:isolate';
import 'dart:math' as math; import 'dart:math' as math;
import '../../../pkg/vm/bin/gen_kernel.dart' as gen_kernel;
import 'package:vm_service/vm_service.dart' as vm_service; import 'package:vm_service/vm_service.dart' as vm_service;
import 'package:vm_service/vm_service_io.dart' as vm_service_io; import 'package:vm_service/vm_service_io.dart' as vm_service_io;
import '../../../pkg/vm/bin/gen_kernel.dart' as gen_kernel;
const String compilerIsolateName = 'isolate-compiler'; const String compilerIsolateName = 'isolate-compiler';
class Result { class Result {

View file

@ -264,12 +264,12 @@ void main() {
setNativeResolverForTest(getRootLibraryUrl()); setNativeResolverForTest(getRootLibraryUrl());
final benchmarks = [ final benchmarks = [
() => Uint8x01(), Uint8x01.new,
() => Int64x20(), Int64x20.new,
() => Doublex01(), Doublex01.new,
() => Doublex20(), Doublex20.new,
() => Handlex01(), Handlex01.new,
() => Handlex20(), Handlex20.new,
]; ];
for (final benchmark in benchmarks) { for (final benchmark in benchmarks) {
benchmark().report(); benchmark().report();

View file

@ -7,6 +7,7 @@
// Benchmark for `Object.hash` and `Object.hashAll`. // Benchmark for `Object.hash` and `Object.hashAll`.
import 'dart:math'; import 'dart:math';
import 'package:benchmark_harness/benchmark_harness.dart'; import 'package:benchmark_harness/benchmark_harness.dart';
int get nextHash => Random().nextInt(0x20000000); int get nextHash => Random().nextInt(0x20000000);
@ -134,11 +135,11 @@ void main() {
generalUses(); generalUses();
final benchmarks = [ final benchmarks = [
() => BenchmarkNode5Hash(), BenchmarkNode5Hash.new,
() => BenchmarkNode5Manual(), BenchmarkNode5Manual.new,
() => BenchmarkNode5List(), BenchmarkNode5List.new,
() => BenchmarkNode5HashHashAll(), BenchmarkNode5HashHashAll.new,
() => BenchmarkNode5ManualHashAll(), BenchmarkNode5ManualHashAll.new,
]; ];
// Warmup all benchmarks so that JIT compilers see full polymorphism before // Warmup all benchmarks so that JIT compilers see full polymorphism before

View file

@ -15,8 +15,8 @@ import '../../BigIntParsePrint/dart/BigIntParsePrint.dart'
as lib_BigIntParsePrint; as lib_BigIntParsePrint;
import '../../Iterators/dart/Iterators.dart' as lib_Iterators; import '../../Iterators/dart/Iterators.dart' as lib_Iterators;
import '../../ListCopy/dart/ListCopy.dart' as lib_ListCopy; import '../../ListCopy/dart/ListCopy.dart' as lib_ListCopy;
import '../../MapCopy/dart/MapCopy.dart' as lib_MapCopy;
import '../../MD5/dart/md5.dart' as lib_MD5; import '../../MD5/dart/md5.dart' as lib_MD5;
import '../../MapCopy/dart/MapCopy.dart' as lib_MapCopy;
import '../../RecordCollections/dart/RecordCollections.dart' import '../../RecordCollections/dart/RecordCollections.dart'
as lib_RecordCollections; as lib_RecordCollections;
import '../../RuntimeType/dart/RuntimeType.dart' as lib_RuntimeType; import '../../RuntimeType/dart/RuntimeType.dart' as lib_RuntimeType;

View file

@ -15,8 +15,8 @@ import '../../BigIntParsePrint/dart/BigIntParsePrint.dart'
deferred as lib_BigIntParsePrint; deferred as lib_BigIntParsePrint;
import '../../Iterators/dart/Iterators.dart' deferred as lib_Iterators; import '../../Iterators/dart/Iterators.dart' deferred as lib_Iterators;
import '../../ListCopy/dart/ListCopy.dart' deferred as lib_ListCopy; import '../../ListCopy/dart/ListCopy.dart' deferred as lib_ListCopy;
import '../../MapCopy/dart/MapCopy.dart' deferred as lib_MapCopy;
import '../../MD5/dart/md5.dart' deferred as lib_MD5; import '../../MD5/dart/md5.dart' deferred as lib_MD5;
import '../../MapCopy/dart/MapCopy.dart' deferred as lib_MapCopy;
import '../../RecordCollections/dart/RecordCollections.dart' import '../../RecordCollections/dart/RecordCollections.dart'
deferred as lib_RecordCollections; deferred as lib_RecordCollections;
import '../../RuntimeType/dart/RuntimeType.dart' deferred as lib_RuntimeType; import '../../RuntimeType/dart/RuntimeType.dart' deferred as lib_RuntimeType;

View file

@ -6,6 +6,7 @@ import 'dart:collection';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:benchmark_harness/benchmark_harness.dart'; import 'package:benchmark_harness/benchmark_harness.dart';
import 'sound_splay_tree.dart'; import 'sound_splay_tree.dart';
List<int> sieve(List<int> initialCandidates) { List<int> sieve(List<int> initialCandidates) {
@ -85,7 +86,7 @@ void busyWork() {
exercise(M2.values); exercise(M2.values);
} }
main() { void main() {
final benchmarks = [ final benchmarks = [
Base(sieve, 'CollectionSieves-SplayTreeSet-removeLoop'), Base(sieve, 'CollectionSieves-SplayTreeSet-removeLoop'),
Base(sieveSound, 'CollectionSieves-SoundSplayTreeSet-removeLoop'), Base(sieveSound, 'CollectionSieves-SoundSplayTreeSet-removeLoop'),
@ -105,6 +106,7 @@ class Base extends BenchmarkBase {
final algorithm; final algorithm;
Base(this.algorithm, String name) : super(name); Base(this.algorithm, String name) : super(name);
static final input = range(2, 5000); static final input = range(2, 5000);
@override
void run() { void run() {
final primes = algorithm(input); final primes = algorithm(input);
if (primes.length != 669) throw 'Wrong result for $name: ${primes.length}'; if (primes.length != 669) throw 'Wrong result for $name: ${primes.length}';

View file

@ -7,17 +7,18 @@ abstract class EfficientLengthIterable<T> extends Iterable<T> {
/// ///
/// This is an efficient operation that doesn't require iterating through /// This is an efficient operation that doesn't require iterating through
/// the elements. /// the elements.
@override
int get length; int get length;
} }
/// Creates errors throw by [Iterable] when the element count is wrong. /// Creates errors throw by [Iterable] when the element count is wrong.
abstract class IterableElementError { abstract class IterableElementError {
/// Error thrown by, e.g., [Iterable.first] when there is no result. /// Error thrown by, e.g., [Iterable.first] when there is no result.
static StateError noElement() => StateError("No element"); static StateError noElement() => StateError('No element');
/// Error thrown by, e.g., [Iterable.single] if there are too many results. /// Error thrown by, e.g., [Iterable.single] if there are too many results.
static StateError tooMany() => StateError("Too many elements"); static StateError tooMany() => StateError('Too many elements');
/// Error thrown by, e.g., [List.setRange] if there are too few elements. /// Error thrown by, e.g., [List.setRange] if there are too few elements.
static StateError tooFew() => StateError("Too few elements"); static StateError tooFew() => StateError('Too few elements');
} }

View file

@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file. // BSD-style license that can be found in the LICENSE file.
import 'dart:collection'; import 'dart:collection';
import 'iterable.dart'; import 'iterable.dart';
typedef _Predicate<T> = bool Function(T value); typedef _Predicate<T> = bool Function(T value);
@ -347,7 +348,7 @@ class SoundSplayTreeMap<inout K, inout V> extends _SoundSplayTree<K>
return map; return map;
} }
static _id(x) => x; static dynamic _id(x) => x;
static void fillMapWithMappedIterable<K, V, E>( static void fillMapWithMappedIterable<K, V, E>(
Map<K, V> map, Iterable<E> iterable, K Function(E element)? key, V Function(E element)? value) { Map<K, V> map, Iterable<E> iterable, K Function(E element)? key, V Function(E element)? value) {
@ -360,8 +361,8 @@ class SoundSplayTreeMap<inout K, inout V> extends _SoundSplayTree<K>
} }
static void fillMapWithIterables(Map map, Iterable keys, Iterable values) { static void fillMapWithIterables(Map map, Iterable keys, Iterable values) {
Iterator keyIterator = keys.iterator; final Iterator keyIterator = keys.iterator;
Iterator valueIterator = values.iterator; final Iterator valueIterator = values.iterator;
bool hasNextKey = keyIterator.moveNext(); bool hasNextKey = keyIterator.moveNext();
bool hasNextValue = valueIterator.moveNext(); bool hasNextValue = valueIterator.moveNext();
@ -373,7 +374,7 @@ class SoundSplayTreeMap<inout K, inout V> extends _SoundSplayTree<K>
} }
if (hasNextKey || hasNextValue) { if (hasNextKey || hasNextValue) {
throw ArgumentError("Iterables do not have same length."); throw ArgumentError('Iterables do not have same length.');
} }
} }
@ -388,17 +389,19 @@ class SoundSplayTreeMap<inout K, inout V> extends _SoundSplayTree<K>
/// It is an error if the two [Iterable]s don't have the same length. /// It is an error if the two [Iterable]s don't have the same length.
factory SoundSplayTreeMap.fromIterables(Iterable<K> keys, Iterable<V> values, factory SoundSplayTreeMap.fromIterables(Iterable<K> keys, Iterable<V> values,
[int Function(K key1, K key2)? compare, bool Function(Object? potentialKey)? isValidKey]) { [int Function(K key1, K key2)? compare, bool Function(Object? potentialKey)? isValidKey]) {
SoundSplayTreeMap<K, V> map = SoundSplayTreeMap<K, V>(compare, isValidKey); final SoundSplayTreeMap<K, V> map = SoundSplayTreeMap<K, V>(compare, isValidKey);
fillMapWithIterables(map, keys, values); fillMapWithIterables(map, keys, values);
return map; return map;
} }
@override
int _compare(K key1, K key2) => _comparator(key1, key2); int _compare(K key1, K key2) => _comparator(key1, key2);
@override
V? operator [](Object? key) { V? operator [](Object? key) {
if (!_validKey(key)) return null; if (!_validKey(key)) return null;
if (_root != null) { if (_root != null) {
int comp = _splay(key as K); final int comp = _splay(key as K);
if (comp == 0) { if (comp == 0) {
return _root!.value; return _root!.value;
} }
@ -406,6 +409,7 @@ class SoundSplayTreeMap<inout K, inout V> extends _SoundSplayTree<K>
return null; return null;
} }
@override
V? remove(Object? key) { V? remove(Object? key) {
if (!_validKey(key)) return null; if (!_validKey(key)) return null;
final _SoundSplayTreeMapNode<K, V>? mapRoot = _remove(key as K) as _SoundSplayTreeMapNode<K, V>?; final _SoundSplayTreeMapNode<K, V>? mapRoot = _remove(key as K) as _SoundSplayTreeMapNode<K, V>?;
@ -413,11 +417,12 @@ class SoundSplayTreeMap<inout K, inout V> extends _SoundSplayTree<K>
return null; return null;
} }
@override
void operator []=(K key, V value) { void operator []=(K key, V value) {
if (key == null) throw ArgumentError(key); if (key == null) throw ArgumentError(key);
// Splay on the key to move the last node on the search path for // Splay on the key to move the last node on the search path for
// the key to the root of the tree. // the key to the root of the tree.
int comp = _splay(key); final int comp = _splay(key);
if (comp == 0) { if (comp == 0) {
_root!.value = value; _root!.value = value;
return; return;
@ -425,15 +430,16 @@ class SoundSplayTreeMap<inout K, inout V> extends _SoundSplayTree<K>
_addNewRoot(_SoundSplayTreeMapNode<K, V>(key, value), comp); _addNewRoot(_SoundSplayTreeMapNode<K, V>(key, value), comp);
} }
V putIfAbsent(K key, V ifAbsent()) { @override
V putIfAbsent(K key, V Function() ifAbsent) {
if (key == null) throw ArgumentError(key); if (key == null) throw ArgumentError(key);
int comp = _splay(key); int comp = _splay(key);
if (comp == 0) { if (comp == 0) {
return _root!.value!; return _root!.value!;
} }
int modificationCount = _modificationCount; final int modificationCount = _modificationCount;
int splayCount = _splayCount; final int splayCount = _splayCount;
V value = ifAbsent(); final V value = ifAbsent();
if (modificationCount != _modificationCount) { if (modificationCount != _modificationCount) {
throw ConcurrentModificationError(this); throw ConcurrentModificationError(this);
} }
@ -446,40 +452,48 @@ class SoundSplayTreeMap<inout K, inout V> extends _SoundSplayTree<K>
return value; return value;
} }
@override
void addAll(Map<K, V> other) { void addAll(Map<K, V> other) {
other.forEach((K key, V value) { other.forEach((K key, V value) {
this[key] = value; this[key] = value;
}); });
} }
@override
bool get isEmpty { bool get isEmpty {
return (_root == null); return (_root == null);
} }
@override
bool get isNotEmpty => !isEmpty; bool get isNotEmpty => !isEmpty;
void forEach(void f(K key, V value)) { @override
Iterator<_SoundSplayTreeNode<K>?> nodes = _SoundSplayTreeNodeIterator<K>(this); void forEach(void Function(K key, V value) f) {
final Iterator<_SoundSplayTreeNode<K>?> nodes = _SoundSplayTreeNodeIterator<K>(this);
while (nodes.moveNext()) { while (nodes.moveNext()) {
_SoundSplayTreeMapNode<K, V> node = nodes.current as _SoundSplayTreeMapNode<K, V>; final _SoundSplayTreeMapNode<K, V> node = nodes.current as _SoundSplayTreeMapNode<K, V>;
f(node.key, node.value!); f(node.key, node.value!);
} }
} }
@override
int get length { int get length {
return _count; return _count;
} }
@override
void clear() { void clear() {
_clear(); _clear();
} }
@override
bool containsKey(Object? key) { bool containsKey(Object? key) {
return _validKey(key) && _splay(key as K) == 0; return _validKey(key) && _splay(key as K) == 0;
} }
@override
bool containsValue(Object? value) { bool containsValue(Object? value) {
int initialSplayCount = _splayCount; final int initialSplayCount = _splayCount;
bool visit(_SoundSplayTreeMapNode<K, V>? node) { bool visit(_SoundSplayTreeMapNode<K, V>? node) {
while (node != null) { while (node != null) {
if (node.value == value) return true; if (node.value == value) return true;
@ -495,8 +509,10 @@ class SoundSplayTreeMap<inout K, inout V> extends _SoundSplayTree<K>
return visit(_root); return visit(_root);
} }
@override
Iterable<K> get keys => _SoundSplayTreeKeyIterable<K>(this); Iterable<K> get keys => _SoundSplayTreeKeyIterable<K>(this);
@override
Iterable<V> get values => _SoundSplayTreeValueIterable<K, V>(this); Iterable<V> get values => _SoundSplayTreeValueIterable<K, V>(this);
/// Get the first key in the map. Returns [:null:] if the map is empty. /// Get the first key in the map. Returns [:null:] if the map is empty.
@ -516,7 +532,7 @@ class SoundSplayTreeMap<inout K, inout V> extends _SoundSplayTree<K>
K? lastKeyBefore(K key) { K? lastKeyBefore(K key) {
if (key == null) throw ArgumentError(key); if (key == null) throw ArgumentError(key);
if (_root == null) return null; if (_root == null) return null;
int comp = _splay(key); final int comp = _splay(key);
if (comp < 0) return _root!.key; if (comp < 0) return _root!.key;
_SoundSplayTreeNode<K>? node = _root!.left; _SoundSplayTreeNode<K>? node = _root!.left;
if (node == null) return null; if (node == null) return null;
@ -531,7 +547,7 @@ class SoundSplayTreeMap<inout K, inout V> extends _SoundSplayTree<K>
K? firstKeyAfter(K key) { K? firstKeyAfter(K key) {
if (key == null) throw ArgumentError(key); if (key == null) throw ArgumentError(key);
if (_root == null) return null; if (_root == null) return null;
int comp = _splay(key); final int comp = _splay(key);
if (comp > 0) return _root!.key; if (comp > 0) return _root!.key;
_SoundSplayTreeNode<K>? node = _root!.right; _SoundSplayTreeNode<K>? node = _root!.right;
if (node == null) return null; if (node == null) return null;
@ -563,12 +579,12 @@ abstract class _SoundSplayTreeIterator<inout K, inout T> implements Iterator<T>
/// ///
/// Not final because some iterators may modify the tree knowingly, /// Not final because some iterators may modify the tree knowingly,
/// and they update the modification count in that case. /// and they update the modification count in that case.
int _modificationCount; final int _modificationCount;
/// Count of splay operations on [_tree] when [_workList] was built. /// Count of splay operations on [_tree] when [_workList] was built.
/// ///
/// If the splay count on [_tree] increases, [_workList] becomes invalid. /// If the splay count on [_tree] increases, [_workList] becomes invalid.
int? _splayCount; final int? _splayCount;
/// Current node. /// Current node.
_SoundSplayTreeNode<K>? _currentNode; _SoundSplayTreeNode<K>? _currentNode;
@ -580,6 +596,7 @@ abstract class _SoundSplayTreeIterator<inout K, inout T> implements Iterator<T>
_findLeftMostDescendant(tree._root); _findLeftMostDescendant(tree._root);
} }
@override
T get current { T get current {
if (_currentNode == null) { if (_currentNode == null) {
throw StateError('Use moveNext to detect the end of an iterator'); throw StateError('Use moveNext to detect the end of an iterator');
@ -612,6 +629,7 @@ abstract class _SoundSplayTreeIterator<inout K, inout T> implements Iterator<T>
} }
} }
@override
bool moveNext() { bool moveNext() {
if (_modificationCount != _tree._modificationCount) { if (_modificationCount != _tree._modificationCount) {
throw ConcurrentModificationError(_tree); throw ConcurrentModificationError(_tree);
@ -637,14 +655,18 @@ abstract class _SoundSplayTreeIterator<inout K, inout T> implements Iterator<T>
} }
class _SoundSplayTreeKeyIterable<inout K> extends EfficientLengthIterable<K> { class _SoundSplayTreeKeyIterable<inout K> extends EfficientLengthIterable<K> {
_SoundSplayTree<K> _tree; final _SoundSplayTree<K> _tree;
_SoundSplayTreeKeyIterable(this._tree); _SoundSplayTreeKeyIterable(this._tree);
@override
int get length => _tree._count; int get length => _tree._count;
@override
bool get isEmpty => _tree._count == 0; bool get isEmpty => _tree._count == 0;
@override
Iterator<K> get iterator => _SoundSplayTreeKeyIterator<K>(_tree); Iterator<K> get iterator => _SoundSplayTreeKeyIterator<K>(_tree);
@override
Set<K> toSet() { Set<K> toSet() {
SoundSplayTreeSet<K> set = SoundSplayTreeSet<K>(_tree._comparator, _tree._validKey); final SoundSplayTreeSet<K> set = SoundSplayTreeSet<K>(_tree._comparator, _tree._validKey);
set._count = _tree._count; set._count = _tree._count;
set._root = set._copyNode(_tree._root); set._root = set._copyNode(_tree._root);
return set; return set;
@ -652,10 +674,13 @@ class _SoundSplayTreeKeyIterable<inout K> extends EfficientLengthIterable<K> {
} }
class _SoundSplayTreeValueIterable<inout K, inout V> extends EfficientLengthIterable<V> { class _SoundSplayTreeValueIterable<inout K, inout V> extends EfficientLengthIterable<V> {
SoundSplayTreeMap<K, V> _map; final SoundSplayTreeMap<K, V> _map;
_SoundSplayTreeValueIterable(this._map); _SoundSplayTreeValueIterable(this._map);
@override
int get length => _map._count; int get length => _map._count;
@override
bool get isEmpty => _map._count == 0; bool get isEmpty => _map._count == 0;
@override
Iterator<V> get iterator => _SoundSplayTreeValueIterator<K, V>(_map); Iterator<V> get iterator => _SoundSplayTreeValueIterator<K, V>(_map);
} }
@ -667,8 +692,9 @@ class _SoundSplayTreeKeyIterator<inout K> extends _SoundSplayTreeIterator<K, K>
class _SoundSplayTreeValueIterator<inout K, inout V> extends _SoundSplayTreeIterator<K, V> { class _SoundSplayTreeValueIterator<inout K, inout V> extends _SoundSplayTreeIterator<K, V> {
_SoundSplayTreeValueIterator(SoundSplayTreeMap<K, V> map) : super(map); _SoundSplayTreeValueIterator(SoundSplayTreeMap<K, V> map) : super(map);
@override
V _getValue(_SoundSplayTreeNode<K> node) { V _getValue(_SoundSplayTreeNode<K> node) {
_SoundSplayTreeMapNode<K, V> mapNode = node as _SoundSplayTreeMapNode<K, V>; final _SoundSplayTreeMapNode<K, V> mapNode = node as _SoundSplayTreeMapNode<K, V>;
return mapNode.value!; return mapNode.value!;
} }
} }
@ -697,10 +723,14 @@ class _SoundSplayTreeNodeIterator<inout K>
/// in that case. /// in that case.
class SoundSplayTreeSet<inout E> extends _SoundSplayTree<E> class SoundSplayTreeSet<inout E> extends _SoundSplayTree<E>
with IterableMixin<E>, SetMixin<E> { with IterableMixin<E>, SetMixin<E> {
@override
_SoundSplayTreeNode<E>? _root; _SoundSplayTreeNode<E>? _root;
@override
final _SoundSplayTreeNode<E> _dummy = _DummySoundSplayTreeNode<E>(); final _SoundSplayTreeNode<E> _dummy = _DummySoundSplayTreeNode<E>();
@override
Comparator<E> _comparator; Comparator<E> _comparator;
@override
_Predicate _validKey; _Predicate _validKey;
/// Create a new [SoundSplayTreeSet] with the given compare function. /// Create a new [SoundSplayTreeSet] with the given compare function.
@ -744,9 +774,9 @@ class SoundSplayTreeSet<inout E> extends _SoundSplayTree<E>
/// ``` /// ```
factory SoundSplayTreeSet.from(Iterable elements, factory SoundSplayTreeSet.from(Iterable elements,
[int Function(E key1, E key2)? compare, bool Function(Object? potentialKey)? isValidKey]) { [int Function(E key1, E key2)? compare, bool Function(Object? potentialKey)? isValidKey]) {
SoundSplayTreeSet<E> result = SoundSplayTreeSet<E>(compare, isValidKey); final SoundSplayTreeSet<E> result = SoundSplayTreeSet<E>(compare, isValidKey);
for (final element in elements) { for (final element in elements) {
E e = element; final E e = element;
result.add(e); result.add(e);
} }
return result; return result;
@ -764,27 +794,36 @@ class SoundSplayTreeSet<inout E> extends _SoundSplayTree<E>
Set<T> _newSet<T>() => Set<T> _newSet<T>() =>
SoundSplayTreeSet<T>((T a, T b) => _comparator(a as E, b as E), _validKey); SoundSplayTreeSet<T>((T a, T b) => _comparator(a as E, b as E), _validKey);
@override
Set<R> cast<R>() => Set.castFrom<E, R>(this, newSet: _newSet); Set<R> cast<R>() => Set.castFrom<E, R>(this, newSet: _newSet);
@override
int _compare(E e1, E e2) => _comparator(e1, e2); int _compare(E e1, E e2) => _comparator(e1, e2);
// From Iterable. // From Iterable.
@override
Iterator<E> get iterator => _SoundSplayTreeKeyIterator<E>(this); Iterator<E> get iterator => _SoundSplayTreeKeyIterator<E>(this);
@override
int get length => _count; int get length => _count;
@override
bool get isEmpty => _root == null; bool get isEmpty => _root == null;
@override
bool get isNotEmpty => _root != null; bool get isNotEmpty => _root != null;
@override
E get first { E get first {
if (_count == 0) throw IterableElementError.noElement(); if (_count == 0) throw IterableElementError.noElement();
return _first!.key; return _first!.key;
} }
@override
E get last { E get last {
if (_count == 0) throw IterableElementError.noElement(); if (_count == 0) throw IterableElementError.noElement();
return _last!.key; return _last!.key;
} }
@override
E get single { E get single {
if (_count == 0) throw IterableElementError.noElement(); if (_count == 0) throw IterableElementError.noElement();
if (_count > 1) throw IterableElementError.tooMany(); if (_count > 1) throw IterableElementError.tooMany();
@ -792,41 +831,47 @@ class SoundSplayTreeSet<inout E> extends _SoundSplayTree<E>
} }
// From Set. // From Set.
@override
bool contains(Object? element) { bool contains(Object? element) {
return _validKey(element) && _splay(element as E) == 0; return _validKey(element) && _splay(element as E) == 0;
} }
@override
bool add(E element) { bool add(E element) {
int compare = _splay(element); final int compare = _splay(element);
if (compare == 0) return false; if (compare == 0) return false;
_addNewRoot(_SoundSplayTreeNode<E>(element), compare); _addNewRoot(_SoundSplayTreeNode<E>(element), compare);
return true; return true;
} }
@override
bool remove(Object? object) { bool remove(Object? object) {
if (!_validKey(object)) return false; if (!_validKey(object)) return false;
return _remove(object as E) != null; return _remove(object as E) != null;
} }
@override
void addAll(Iterable<E> elements) { void addAll(Iterable<E> elements) {
for (E element in elements) { for (E element in elements) {
int compare = _splay(element); final int compare = _splay(element);
if (compare != 0) { if (compare != 0) {
_addNewRoot(_SoundSplayTreeNode<E>(element), compare); _addNewRoot(_SoundSplayTreeNode<E>(element), compare);
} }
} }
} }
@override
void removeAll(Iterable<Object?> elements) { void removeAll(Iterable<Object?> elements) {
for (Object? element in elements) { for (Object? element in elements) {
if (_validKey(element)) _remove(element as E); if (_validKey(element)) _remove(element as E);
} }
} }
@override
void retainAll(Iterable<Object?> elements) { void retainAll(Iterable<Object?> elements) {
// Build a set with the same sense of equality as this set. // Build a set with the same sense of equality as this set.
SoundSplayTreeSet<E> retainSet = SoundSplayTreeSet<E>(_comparator, _validKey); final SoundSplayTreeSet<E> retainSet = SoundSplayTreeSet<E>(_comparator, _validKey);
int modificationCount = _modificationCount; final int modificationCount = _modificationCount;
for (Object? object in elements) { for (Object? object in elements) {
if (modificationCount != _modificationCount) { if (modificationCount != _modificationCount) {
// The iterator should not have side effects. // The iterator should not have side effects.
@ -845,35 +890,39 @@ class SoundSplayTreeSet<inout E> extends _SoundSplayTree<E>
} }
} }
@override
E? lookup(Object? object) { E? lookup(Object? object) {
if (!_validKey(object)) return null; if (!_validKey(object)) return null;
int comp = _splay(object as E); final int comp = _splay(object as E);
if (comp != 0) return null; if (comp != 0) return null;
return _root!.key; return _root!.key;
} }
@override
Set<E> intersection(Set<Object?> other) { Set<E> intersection(Set<Object?> other) {
Set<E> result = SoundSplayTreeSet<E>(_comparator, _validKey); final Set<E> result = SoundSplayTreeSet<E>(_comparator, _validKey);
for (E element in this) { for (E element in this) {
if (other.contains(element)) result.add(element); if (other.contains(element)) result.add(element);
} }
return result; return result;
} }
@override
Set<E> difference(Set<Object?> other) { Set<E> difference(Set<Object?> other) {
Set<E> result = SoundSplayTreeSet<E>(_comparator, _validKey); final Set<E> result = SoundSplayTreeSet<E>(_comparator, _validKey);
for (E element in this) { for (E element in this) {
if (!other.contains(element)) result.add(element); if (!other.contains(element)) result.add(element);
} }
return result; return result;
} }
@override
Set<E> union(Set<E> other) { Set<E> union(Set<E> other) {
return _clone()..addAll(other); return _clone()..addAll(other);
} }
SoundSplayTreeSet<E> _clone() { SoundSplayTreeSet<E> _clone() {
var set = SoundSplayTreeSet<E>(_comparator, _validKey); final set = SoundSplayTreeSet<E>(_comparator, _validKey);
set._count = _count; set._count = _count;
set._root = _copyNode(_root); set._root = _copyNode(_root);
return set; return set;
@ -888,11 +937,14 @@ class SoundSplayTreeSet<inout E> extends _SoundSplayTree<E>
..right = _copyNode(node.right)); ..right = _copyNode(node.right));
} }
@override
void clear() { void clear() {
_clear(); _clear();
} }
@override
Set<E> toSet() => _clone(); Set<E> toSet() => _clone();
@override
String toString() => IterableBase.iterableToFullString(this, '{', '}'); String toString() => IterableBase.iterableToFullString(this, '{', '}');
} }

View file

@ -27,8 +27,8 @@
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:expect/expect.dart';
import 'package:benchmark_harness/benchmark_harness.dart'; import 'package:benchmark_harness/benchmark_harness.dart';
import 'package:expect/expect.dart';
import 'match_class.dart' as match_class; import 'match_class.dart' as match_class;
import 'match_enum.dart' as match_enum; import 'match_enum.dart' as match_enum;
@ -85,8 +85,9 @@ class Benchmark extends BenchmarkBase {
return repeats + padding; return repeats + padding;
} }
static convert(String s) => Uint8List.fromList(s.codeUnits); static Uint8List convert(String s) => Uint8List.fromList(s.codeUnits);
@override
void run() { void run() {
Expect.equals(true, match(testInput)); Expect.equals(true, match(testInput));
} }