blob: 56fc450d9236f2bac30b75b6d1382b5f0f6d82dc [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/// Jenkins hash function, optimized for small integers.
//
// Borrowed from the dart sdk: sdk/lib/math/jenkins_smi_hash.dart.
class _Jenkins {
static int combine(final int h, Object o) {
assert(o is! Iterable);
int hash = h;
hash = 0x1fffffff & (hash + o.hashCode);
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
return hash ^ (hash >> 6);
}
static int finish(final int h) {
int hash = h;
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
hash = hash ^ (hash >> 11);
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
}
}
/// Combine the [Object.hashCode] values of an arbitrary number of objects from
/// an [Iterable] into one value. This function will return the same value if
/// given null as if given an empty list.
int deepHash(Iterable<Object> arguments) {
int result = 0;
if (arguments != null) {
for (Object argument in arguments) {
if (argument is Iterable) {
argument = deepHash(argument);
}
result = _Jenkins.combine(result, argument);
}
}
return _Jenkins.finish(result);
}
/// Deep equality helper function.
bool deepEquals(dynamic a, dynamic b) {
// iterable
if (a is Iterable) {
// ignore: avoid_bool_literals_in_conditional_expressions
return (b is Iterable) ?
_deepEqualsOfIterable(a, b) :
false;
}
// map
if (a is Map) {
// ignore: avoid_bool_literals_in_conditional_expressions
return (b is Map) ?
_deepEqualsOfMap(a, b) :
false;
}
// default
return a == b;
}
/// Deep equality helper function for Iterables.
bool _deepEqualsOfIterable(Iterable<Object> a, Iterable<Object> b) {
if (a.length != b.length) {
return false;
}
final ai = a.iterator;
final bi = b.iterator;
while (ai.moveNext() && bi.moveNext()) {
if (!deepEquals(ai.current, bi.current)) {
return false;
}
}
return true;
}
/// Deep equality helper function for Maps.
bool _deepEqualsOfMap(Map a, Map b) {
if (a.length != b.length) {
return false;
}
for (var key in a.keys) {
if (!b.containsKey(key)) {
return false;
}
final aCurrent = a[key];
final bCurrent = b[key];
if (!deepEquals(aCurrent, bCurrent)) {
return false;
}
}
return true;
}