From 10483f5357134ad6a0d6211e30a06e08512f9dc1 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Wed, 10 Jan 2018 17:58:29 -0800 Subject: [PATCH 1/2] Use explicit keys for often accessed closures --- lib/src/model.dart | 10 ++++++---- lib/src/model_utils.dart | 5 +++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/src/model.dart b/lib/src/model.dart index 90ca35802f..fbd024bdc7 100644 --- a/lib/src/model.dart +++ b/lib/src/model.dart @@ -1560,8 +1560,8 @@ abstract class GetterSetterCombo implements ModelElement { if (targetClass.name == target.name) { return original.replaceAll(constructorName, "${target.linkedName}"); } - return original.replaceAll( - "${targetClass.name}.${target.name}", "${targetClass.linkedName}.${target.linkedName}"); + return original.replaceAll("${targetClass.name}.${target.name}", + "${targetClass.linkedName}.${target.linkedName}"); } String _constantValueBase() { @@ -2892,7 +2892,8 @@ abstract class ModelElement extends Canonicalization /// /// For example: libraryName.className.methodName @override - String get fullyQualifiedName => _memoizer.memoized(_buildFullyQualifiedName); + String get fullyQualifiedName => _memoizer.memoized(_buildFullyQualifiedName, + altKey: 'fullyQualifiedName'); String _fullyQualifiedNameWithoutLibrary() { // Remember, periods are legal in library names. @@ -2904,7 +2905,8 @@ abstract class ModelElement extends Canonicalization // library.fullyQualifiedName seems somehow to break things. //String get fullyQualifiedNameWithoutLibrary => _memoizer.memoized2(fullyQualifiedName.replaceFirst, "${library.fullyQualifiedName}.", ''); String get fullyQualifiedNameWithoutLibrary => - _memoizer.memoized(_fullyQualifiedNameWithoutLibrary); + _memoizer.memoized(_fullyQualifiedNameWithoutLibrary, + altKey: 'fullyQualifiedNameWithoutLibrary'); String get sourceFileName => element.source.fullName; diff --git a/lib/src/model_utils.dart b/lib/src/model_utils.dart index 5dbcfbf622..8a32af1ee3 100644 --- a/lib/src/model_utils.dart +++ b/lib/src/model_utils.dart @@ -266,8 +266,9 @@ class Memoizer { /// Calls and caches the return value of [f]() if not in the cache, then /// returns the cached value of [f](). - R memoized(Function f) { - _HashableList key = new _HashableList([f]); + R memoized(Function f, {String altKey}) { + Object obj = altKey ?? f; + _HashableList key = new _HashableList([obj]); return _cacheIfAbsent(key, f); } From 5ec1c0eadbc52c065a5406f86d464451279066f7 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Wed, 10 Jan 2018 18:28:42 -0800 Subject: [PATCH 2/2] _HashableList: don't use UnodifiableListView Adds unnecessary overhead in a perf-critical case Also cache the hashCode --- lib/src/model_utils.dart | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/src/model_utils.dart b/lib/src/model_utils.dart index 8a32af1ee3..b21e9e4e99 100644 --- a/lib/src/model_utils.dart +++ b/lib/src/model_utils.dart @@ -172,15 +172,17 @@ String crossdartifySource( /// An UnmodifiableListView that computes equality and hashCode based on the /// equality and hashCode of its contained objects. -class _HashableList extends UnmodifiableListView { - _HashableList(Iterable iterable) : super(iterable); +class _HashableList { + final List _source; + int _hashCache; + _HashableList(this._source); @override bool operator ==(other) { if (other is _HashableList) { - if (this.length == other.length) { - for (var index = 0; index < length; ++index) { - if (this[index] != other[index]) return false; + if (_source.length == other._source.length) { + for (var index = 0; index < _source.length; ++index) { + if (_source[index] != other._source[index]) return false; } return true; } @@ -189,7 +191,7 @@ class _HashableList extends UnmodifiableListView { } @override - get hashCode => hashObjects(this); + get hashCode => _hashCache ??= hashObjects(_source); } /// Like [Memoizer], except in checked mode will validate that the value of the @@ -252,11 +254,11 @@ class ValidatingMemoizer extends Memoizer { /// ``` class Memoizer { /// Map of a function and its positional parameters (if any), to a value. - Map<_HashableList, dynamic> _memoizationTable = new Map(); + final Map<_HashableList, dynamic> _memoizationTable = new HashMap(); /// Reset the memoization table, forcing calls of the underlying functions. void invalidateMemos() { - _memoizationTable = new Map(); + _memoizationTable.clear(); } /// A wrapper around putIfAbsent, exposed to allow overrides.