| // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| // 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. |
| |
| // @dart=2.9 |
| |
| import "dart:math"; |
| import "dart:typed_data"; |
| |
| import "package:expect/expect.dart"; |
| |
| main() { |
| const nan = double.nan; |
| const inf = double.infinity; |
| |
| int hash1234 = Object.hash(1, 2, 3, 4); |
| Expect.type<int>(hash1234); |
| Expect.equals(hash1234, Object.hash(1, 2, 3, 4)); // Consistent. |
| Expect.equals(hash1234, Object.hashAll([1, 2, 3, 4])); |
| Expect.equals(hash1234, Object.hashAll(Uint8List.fromList([1, 2, 3, 4]))); |
| |
| Expect.notEquals(hash1234, Object.hash(1, 2, 3, 4, null)); |
| |
| Expect.equals(Object.hash(1, 2, 3, 4, 5, 6, 7, 8, 9), |
| Object.hashAll([1, 2, 3, 4, 5, 6, 7, 8, 9])); |
| |
| // Check that we can call `hash` with 2-20 arguments, |
| // and they all agree with `hashAll`. |
| var random = Random(); |
| for (var i = 2; i <= 20; i++) { |
| var arguments = [for (var j = 0; j < i; j++) random.nextInt(256)]; |
| var hashAll = Object.hashAll(arguments); |
| var hash = Function.apply(Object.hash, arguments); |
| Expect.equals( |
| hashAll, |
| hash, |
| "hashAll and hash disagrees for $i values:\n" |
| "$arguments"); |
| } |
| |
| // Works for all kinds of objects; |
| int varHash = Object.hash( |
| "string", 3, nan, true, null, Type, #Symbol, const Object(), function); |
| Expect.equals( |
| varHash, |
| Object.hashAll([ |
| "string", |
| 3, |
| nan, |
| true, |
| null, |
| Type, |
| #Symbol, |
| const Object(), |
| function |
| ])); |
| |
| // Object doesn't matter, just its hash code. |
| Expect.equals(hash1234, |
| Object.hash(Hashable(1), Hashable(2), Hashable(3), Hashable(4))); |
| |
| // It's potentially possible to get a conflict, but it doesn't happen here. |
| Expect.notEquals("str".hashCode, Object.hashAll(["str"])); |
| |
| var hash12345 = Object.hashAllUnordered([1, 2, 3, 4, 5]); |
| for (var p in permutations([1, 2, 3, 4, 5])) { |
| Expect.equals(hash12345, Object.hashAllUnordered(p)); |
| } |
| Expect.notEquals( |
| Object.hashAllUnordered(["a", "a"]), Object.hashAllUnordered(["a"])); |
| |
| Expect.notEquals(Object.hashAllUnordered(["a", "a"]), |
| Object.hashAllUnordered(["a", "a", "a", "a"])); |
| |
| Expect.notEquals(Object.hashAllUnordered(["a", "b"]), |
| Object.hashAllUnordered(["a", "a", "a", "b"])); |
| |
| /// Unordered hashing works for all kinds of objects. |
| var unorderHash = Object.hashAllUnordered([ |
| "string", |
| 3, |
| nan, |
| true, |
| null, |
| Type, |
| #Symbol, |
| const Object(), |
| function, |
| ]); |
| |
| var unorderHash2 = Object.hashAllUnordered([ |
| true, |
| const Object(), |
| 3, |
| function, |
| Type, |
| "string", |
| null, |
| nan, |
| #Symbol, |
| ]); |
| Expect.equals(unorderHash, unorderHash2); |
| } |
| |
| /// Lazily emits all permutations of [values]. |
| /// |
| /// Modifes [values] rather than create a new list. |
| /// The [values] list is guaranteed to end up in its original state |
| /// after all permutations have been read. |
| Iterable<List<T>> permutations<T>(List<T> values) { |
| Iterable<List<T>> recPermute(int end) sync* { |
| if (end == 1) { |
| yield values; |
| return; |
| } |
| for (var i = 0; i < end; i++) { |
| yield* recPermute(end - 1); |
| // Rotate values[i:]. |
| var tmp = values.first; |
| for (var k = 1; k < end; k++) values[k - 1] = values[k]; |
| values[end - 1] = tmp; |
| } |
| } |
| |
| return recPermute(values.length); |
| } |
| |
| // static function, used as constant value. |
| void function() {} |
| |
| class Hashable { |
| final Object o; |
| Hashable(this.o); |
| bool operator ==(Object other) => other is Hashable && o == other.o; |
| int get hashCode => o.hashCode; |
| } |