Fix KeySet<T> (and LogicalKeySet, PhysicalKeySet) hashCode calculation (#38936)
This fixes the hashCode calculation for KeySet<T> so that it doesn't depend on the insertion order of the keys in the set. The fix involves switching from Set<T> to HashSet<T> internally, so that the iteration order is stable around the hash values of the inserted keys, and not the insertion order. This matters when hashList is called in KeySet<T>.hashCode to build the hash value of the contents of the internal set. Fixes #38919
This commit is contained in:
parent
01a5d112d5
commit
055c548902
@ -2,6 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
@ -39,7 +41,7 @@ class KeySet<T extends KeyboardKey> extends Diagnosticable {
|
||||
T key3,
|
||||
T key4,
|
||||
]) : assert(key1 != null),
|
||||
_keys = <T>{key1} {
|
||||
_keys = HashSet<T>()..add(key1) {
|
||||
int count = 1;
|
||||
if (key2 != null) {
|
||||
_keys.add(key2);
|
||||
@ -74,11 +76,14 @@ class KeySet<T extends KeyboardKey> extends Diagnosticable {
|
||||
: assert(keys != null),
|
||||
assert(keys.isNotEmpty),
|
||||
assert(!keys.contains(null)),
|
||||
_keys = keys;
|
||||
_keys = HashSet<T>.from(keys);
|
||||
|
||||
/// Returns an unmodifiable view of the [KeyboardKey]s in this [KeySet].
|
||||
Set<T> get keys => UnmodifiableSetView<T>(_keys);
|
||||
final Set<T> _keys;
|
||||
// This needs to be a hash set to be sure that the hashCode accessor returns
|
||||
// consistent results. LinkedHashSet (the default Set implementation) depends
|
||||
// upon insertion order, and HashSet does not.
|
||||
final HashSet<T> _keys;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
|
@ -167,8 +167,26 @@ void main() {
|
||||
final LogicalKeySet set2 = LogicalKeySet(
|
||||
LogicalKeyboardKey.keyA,
|
||||
LogicalKeyboardKey.keyB,
|
||||
LogicalKeyboardKey.keyC,
|
||||
LogicalKeyboardKey.keyD,
|
||||
);
|
||||
final LogicalKeySet set3 = LogicalKeySet(
|
||||
LogicalKeyboardKey.keyD,
|
||||
LogicalKeyboardKey.keyC,
|
||||
LogicalKeyboardKey.keyB,
|
||||
LogicalKeyboardKey.keyA,
|
||||
);
|
||||
final LogicalKeySet set4 = LogicalKeySet.fromSet(<LogicalKeyboardKey>{
|
||||
LogicalKeyboardKey.keyD,
|
||||
LogicalKeyboardKey.keyC,
|
||||
LogicalKeyboardKey.keyB,
|
||||
LogicalKeyboardKey.keyA,}
|
||||
);
|
||||
final Map<LogicalKeySet, String> map = <LogicalKeySet, String>{set1: 'one'};
|
||||
expect(set2 == set3, isTrue);
|
||||
expect(set2 == set4, isTrue);
|
||||
expect(set2.hashCode == set3.hashCode, isTrue);
|
||||
expect(set2.hashCode == set4.hashCode, isTrue);
|
||||
expect(map.containsKey(set1), isTrue);
|
||||
expect(map.containsKey(LogicalKeySet(LogicalKeyboardKey.keyA)), isTrue);
|
||||
expect(
|
||||
@ -176,6 +194,8 @@ void main() {
|
||||
equals(LogicalKeySet.fromSet(<LogicalKeyboardKey>{
|
||||
LogicalKeyboardKey.keyA,
|
||||
LogicalKeyboardKey.keyB,
|
||||
LogicalKeyboardKey.keyC,
|
||||
LogicalKeyboardKey.keyD,
|
||||
})));
|
||||
});
|
||||
test('$KeySet diagnostics work.', () {
|
||||
|
Loading…
x
Reference in New Issue
Block a user