| // 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. | |
| 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]. | |
| /// | |
| /// Modifies [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; | |
| } |