From 670c642701c960e1f861ce08a25e3c0b46aef6af Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Tue, 12 Dec 2017 13:35:15 -0800 Subject: [PATCH 01/11] New class memoizer for simplifying Dartdoc's caching --- lib/src/model_utils.dart | 135 +++++++++++++++++++++++++++++++++++++ test/model_utils_test.dart | 72 ++++++++++++++++++++ 2 files changed, 207 insertions(+) diff --git a/lib/src/model_utils.dart b/lib/src/model_utils.dart index 0b8dd946a3..1271b8feb7 100644 --- a/lib/src/model_utils.dart +++ b/lib/src/model_utils.dart @@ -4,6 +4,7 @@ library dartdoc.model_utils; +import 'dart:collection'; import 'dart:convert'; import 'dart:io'; @@ -12,6 +13,8 @@ import 'package:analyzer/src/generated/engine.dart'; import 'package:analyzer/src/generated/sdk.dart'; import 'package:analyzer/src/generated/source_io.dart'; import 'package:dartdoc/src/model.dart'; +import 'package:quiver_hashcode/hashcode.dart'; +import 'package:tuple/tuple.dart'; import 'config.dart'; @@ -166,3 +169,135 @@ String crossdartifySource( } return newSource; } + +/// 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); + + @override + bool operator==(other) { + if (this.length == other.length) { + for (var index = 0; index < length; ++index) { + if (this[index] != other[index]) return false; + } + return true; + } + return false; + } + + @override + get hashCode => hashObjects(this); +} + +/// Extend or use as a mixin to track object-specific cached values, or +/// instantiate directly to track other values. +class MethodMemoizer { + /// Map of a function and its positional parameters (if any), to a value. + Map, dynamic> _memoizationTable; + + MethodMemoizer() { + invalidateMemos(); + } + + /// Reset the memoization table, forcing calls of the underlying functions. + void invalidateMemos() { _memoizationTable = new Map(); } + + /// Calls and caches the return value of [f]() if not in the cache, then + /// returns the cached value of [f](). + R memoized(Function f) { + Tuple2 key = new Tuple2(f, new HashableList([])); + if (!_memoizationTable.containsKey(key)) { + _memoizationTable[key] = f(); + } + return _memoizationTable[key]; + } + + /// Calls and caches the return value of [f]([param1]) if not in the cache, then + /// returns the cached value of [f]([param1]). + R memoized1(R Function(A) f, A param1) { + Tuple2 key = new Tuple2(f, new HashableList([param1])); + if (!_memoizationTable.containsKey(key)) { + _memoizationTable[key] = f(param1); + } + return _memoizationTable[key]; + } + + /// Calls and caches the return value of [f]([param1], [param2]) if not in the + /// cache, then returns the cached value of [f]([param1], [param2]). + R memoized2(R Function(A, B) f, A param1, B param2) { + Tuple2 key = new Tuple2(f, new HashableList([param1, param2])); + if (!_memoizationTable.containsKey(key)) { + _memoizationTable[key] = f(param1, param2); + } + return _memoizationTable[key]; + } + + /// Calls and caches the return value of [f]([param1], [param2], [param3]) if + /// not in the cache, then returns the cached value of [f]([param1], + /// [param2], [param3]). + R memoized3(R Function(A, B, C) f, A param1, B param2, C param3) { + Tuple2 key = new Tuple2(f, new HashableList([param1, param2, param3])); + if (!_memoizationTable.containsKey(key)) { + _memoizationTable[key] = f(param1, param2, param3); + } + return _memoizationTable[key]; + } + + /// Calls and caches the return value of [f]([param1], [param2], [param3], + /// [param4]) if not in the cache, then returns the cached value of + /// [f]([param1], [param2], [param3], [param4]). + R memoized4(R Function(A, B, C, D) f, A param1, B param2, C param3, D param4) { + Tuple2 key = new Tuple2(f, new HashableList([param1, param2, param3, param4])); + if (!_memoizationTable.containsKey(key)) { + _memoizationTable[key] = f(param1, param2, param3, param4); + } + return _memoizationTable[key]; + } + + /// Calls and caches the return value of [f]([param1], [param2], [param3], + /// [param4], [param5]) if not in the cache, then returns the cached value of [f]( + /// [param1], [param2], [param3], [param4], [param5]). + R memoized5(R Function(A, B, C, D, E) f, A param1, B param2, C param3, D param4, E param5) { + Tuple2 key = new Tuple2(f, new HashableList([param1, param2, param3, param4, param5])); + if (!_memoizationTable.containsKey(key)) { + _memoizationTable[key] = f(param1, param2, param3, param4, param5); + } + return _memoizationTable[key]; + } + + /// Calls and caches the return value of [f]([param1], [param2], [param3], + /// [param4], [param5], [param6]) if not in the cache, then returns the cached + /// value of [f]([param1], [param2], [param3], [param4], [param5], [param6]). + R memoized6(R Function(A, B, C, D, E, F) f, A param1, B param2, C param3, D param4, E param5, F param6) { + Tuple2 key = new Tuple2(f, new HashableList([param1, param2, param3, param4, param5, param6])); + if (!_memoizationTable.containsKey(key)) { + _memoizationTable[key] = f(param1, param2, param3, param4, param5, param6); + } + return _memoizationTable[key]; + } + + /// Calls and caches the return value of [f]([param1], [param2], [param3], + /// [param4], [param5], [param6], [param7]) if not in the cache, then returns + /// the cached value of [f]([param1], [param2], [param3], [param4], [param5], + /// [param6], [param7]). + R memoized7(R Function(A, B, C, D, E, F, G) f, A param1, B param2, C param3, D param4, E param5, F param6, G param7) { + Tuple2 key = new Tuple2(f, new HashableList([param1, param2, param3, param4, param5, param6, param7])); + if (!_memoizationTable.containsKey(key)) { + _memoizationTable[key] = f(param1, param2, param3, param4, param5, param6, param7); + } + return _memoizationTable[key]; + } + + /// Calls and caches the return value of [f]([param1], [param2], [param3], + /// [param4], [param5], [param6], [param7], [param8]) if not in the cache, + /// then returns the cached value of [f]([param1], [param2], [param3], + /// [param4], [param5], [param6], [param7], [param8]). + R memoized8(R Function(A, B, C, D, E, F, G, H) f, A param1, B param2, C param3, D param4, E param5, F param6, G param7, H param8) { + Tuple2 key = new Tuple2(f, new HashableList([param1, param2, param3, param4, param5, param6, param7, param8])); + if (!_memoizationTable.containsKey(key)) { + _memoizationTable[key] = f(param1, param2, param3, param4, param5, param6, param7, param8); + } + return _memoizationTable[key]; + } +} \ No newline at end of file diff --git a/test/model_utils_test.dart b/test/model_utils_test.dart index 7bc35cdfe2..cb87b2d16d 100644 --- a/test/model_utils_test.dart +++ b/test/model_utils_test.dart @@ -7,6 +7,38 @@ library dartdoc.model_utils_test; import 'package:dartdoc/src/model_utils.dart'; import 'package:test/test.dart'; +class MemoizerUser extends MethodMemoizer { + int foo = 0; + // These are actually not things you would ordinarily memoize, because + // they change. But they are useful for testing. + int _toMemoize() { return foo++; } + int get toMemoize => memoized(_toMemoize); + + String _memoizedParameter1(String param) => "${foo++} ${param}"; + String memoizedParameter1(String param) => memoized1(_memoizedParameter1, param); + + String _memoizedParameter2(String param, String param2) => "${foo++} ${param} ${param2}"; + String memoizedParameter2(String param, String param2) => memoized2(_memoizedParameter2, param, param2); + + String _memoizedParameter3(String param, String param2, String param3) => "${foo++} ${param} ${param2} ${param3}"; + String memoizedParameter3(String param, String param2, String param3) => memoized3(_memoizedParameter3, param, param2, param3); + + String _memoizedParameter4(String param, String param2, String param3, String param4) => "${foo++} ${param} ${param2} ${param3} ${param4}"; + String memoizedParameter4(String param, String param2, String param3, String param4) => memoized4(_memoizedParameter4, param, param2, param3, param4); + + String _memoizedParameter5(String param, String param2, String param3, String param4, String param5) => "${foo++} ${param} ${param2} ${param3} ${param4} ${param5}"; + String memoizedParameter5(String param, String param2, String param3, String param4, String param5) => memoized5(_memoizedParameter5, param, param2, param3, param4, param5); + + String _memoizedParameter6(String param, String param2, String param3, String param4, String param5, String param6) => "${foo++} ${param} ${param2} ${param3} ${param4} ${param5} ${param6}"; + String memoizedParameter6(String param, String param2, String param3, String param4, String param5, String param6) => memoized6(_memoizedParameter6, param, param2, param3, param4, param5, param6); + + String _memoizedParameter7(String param, String param2, String param3, String param4, String param5, String param6, String param7) => "${foo++} ${param} ${param2} ${param3} ${param4} ${param5} ${param6} ${param7}"; + String memoizedParameter7(String param, String param2, String param3, String param4, String param5, String param6, String param7) => memoized7(_memoizedParameter7, param, param2, param3, param4, param5, param6, param7); + + String _memoizedParameter8(String param, String param2, String param3, String param4, String param5, String param6, String param7, String param8) => "${foo++} ${param} ${param2} ${param3} ${param4} ${param5} ${param6} ${param7} ${param8}"; + String memoizedParameter8(String param, String param2, String param3, String param4, String param5, String param6, String param7, String param8) => memoized8(_memoizedParameter8, param, param2, param3, param4, param5, param6, param7, param8); +} + void main() { group('model_utils stripIndentFromSource', () { test('no indent', () { @@ -52,4 +84,44 @@ void main() { 'void foo() {\n print(1);\n}\n'); }); }); + + group('model_utils MethodMemoizer', () { + test('basic memoization and invalidation', () { + var m = new MemoizerUser(); + expect(m.toMemoize, equals(0), reason: "initialization problem"); + expect(m.toMemoize, equals(0), reason: "failed to memoize"); + m.invalidateMemos(); + expect(m.toMemoize, equals(1), reason: "failed to invalidate"); + }); + + test('memoization of a method with parameter', () { + var m = new MemoizerUser(); + expect(m.memoizedParameter1("hello"), equals("0 hello"), reason: "initialization problem"); + expect(m.memoizedParameter1("hello"), equals("0 hello"), reason: "failed to memoize"); + expect(m.memoizedParameter1("goodbye"), equals("1 goodbye")); + expect(m.memoizedParameter1("something"), equals("2 something")); + m.invalidateMemos(); + expect(m.memoizedParameter1("hello"), equals("3 hello"), reason: "failed to invalidate"); + }); + + test('memoization of many parameters', () { + var m = new MemoizerUser(); + expect(m.memoizedParameter1("hello"), equals("0 hello")); + expect(m.memoizedParameter2("hello", "obi"), equals("1 hello obi")); + expect(m.memoizedParameter3("hello", "obi", "wan"), equals("2 hello obi wan")); + expect(m.memoizedParameter4("hello", "obi", "wan", "how"), equals("3 hello obi wan how")); + expect(m.memoizedParameter5("hello", "obi", "wan", "how", "are"), equals("4 hello obi wan how are")); + expect(m.memoizedParameter6("hello", "obi", "wan", "how", "are", "you"), equals("5 hello obi wan how are you")); + expect(m.memoizedParameter7("hello", "obi", "wan", "how", "are", "you", "doing"), equals("6 hello obi wan how are you doing")); + expect(m.memoizedParameter8("hello", "obi", "wan", "how", "are", "you", "doing", "today"), equals("7 hello obi wan how are you doing today")); + expect(m.memoizedParameter1("hello"), equals("0 hello")); + expect(m.memoizedParameter2("hello", "obi"), equals("1 hello obi")); + expect(m.memoizedParameter3("hello", "obi", "wan"), equals("2 hello obi wan")); + expect(m.memoizedParameter4("hello", "obi", "wan", "how"), equals("3 hello obi wan how")); + expect(m.memoizedParameter5("hello", "obi", "wan", "how", "are"), equals("4 hello obi wan how are")); + expect(m.memoizedParameter6("hello", "obi", "wan", "how", "are", "you"), equals("5 hello obi wan how are you")); + expect(m.memoizedParameter7("hello", "obi", "wan", "how", "are", "you", "doing"), equals("6 hello obi wan how are you doing")); + expect(m.memoizedParameter8("hello", "obi", "wan", "how", "are", "you", "doing", "today"), equals("7 hello obi wan how are you doing today")); + }); + }); } From 851cfb03e62e9c75803576c874817acc8235aa95 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Tue, 12 Dec 2017 13:59:38 -0800 Subject: [PATCH 02/11] Reduce copy-pasting to bare minimum --- lib/src/model_utils.dart | 75 ++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 45 deletions(-) diff --git a/lib/src/model_utils.dart b/lib/src/model_utils.dart index 1271b8feb7..31c48d6314 100644 --- a/lib/src/model_utils.dart +++ b/lib/src/model_utils.dart @@ -190,11 +190,15 @@ class HashableList extends UnmodifiableListView { get hashCode => hashObjects(this); } +class _MemoKey extends Tuple2 { + _MemoKey(Function f, HashableList l) : super(f, l) {} +} + /// Extend or use as a mixin to track object-specific cached values, or /// instantiate directly to track other values. class MethodMemoizer { /// Map of a function and its positional parameters (if any), to a value. - Map, dynamic> _memoizationTable; + Map<_MemoKey, dynamic> _memoizationTable; MethodMemoizer() { invalidateMemos(); @@ -203,78 +207,65 @@ class MethodMemoizer { /// Reset the memoization table, forcing calls of the underlying functions. void invalidateMemos() { _memoizationTable = new Map(); } - /// Calls and caches the return value of [f]() if not in the cache, then - /// returns the cached value of [f](). - R memoized(Function f) { - Tuple2 key = new Tuple2(f, new HashableList([])); + // Never write this if statement again. + R _getOrUpdateCache(R Function() f, _MemoKey key) { if (!_memoizationTable.containsKey(key)) { _memoizationTable[key] = f(); } return _memoizationTable[key]; } + /// Calls and caches the return value of [f]() if not in the cache, then + /// returns the cached value of [f](). + R memoized(Function f) { + _MemoKey key = new _MemoKey(f, new HashableList([])); + return _getOrUpdateCache(() => f(), key); + } + /// Calls and caches the return value of [f]([param1]) if not in the cache, then /// returns the cached value of [f]([param1]). R memoized1(R Function(A) f, A param1) { - Tuple2 key = new Tuple2(f, new HashableList([param1])); - if (!_memoizationTable.containsKey(key)) { - _memoizationTable[key] = f(param1); - } - return _memoizationTable[key]; + _MemoKey key = new _MemoKey(f, new HashableList([param1])); + return _getOrUpdateCache(() => f(param1), key); } /// Calls and caches the return value of [f]([param1], [param2]) if not in the /// cache, then returns the cached value of [f]([param1], [param2]). R memoized2(R Function(A, B) f, A param1, B param2) { - Tuple2 key = new Tuple2(f, new HashableList([param1, param2])); - if (!_memoizationTable.containsKey(key)) { - _memoizationTable[key] = f(param1, param2); - } - return _memoizationTable[key]; + _MemoKey key = new _MemoKey(f, new HashableList([param1, param2])); + return _getOrUpdateCache(() => f(param1, param2), key); } /// Calls and caches the return value of [f]([param1], [param2], [param3]) if /// not in the cache, then returns the cached value of [f]([param1], /// [param2], [param3]). R memoized3(R Function(A, B, C) f, A param1, B param2, C param3) { - Tuple2 key = new Tuple2(f, new HashableList([param1, param2, param3])); - if (!_memoizationTable.containsKey(key)) { - _memoizationTable[key] = f(param1, param2, param3); - } - return _memoizationTable[key]; + _MemoKey key = new _MemoKey(f, new HashableList([param1, param2, param3])); + return _getOrUpdateCache(() => f(param1, param2, param3), key); } /// Calls and caches the return value of [f]([param1], [param2], [param3], /// [param4]) if not in the cache, then returns the cached value of /// [f]([param1], [param2], [param3], [param4]). R memoized4(R Function(A, B, C, D) f, A param1, B param2, C param3, D param4) { - Tuple2 key = new Tuple2(f, new HashableList([param1, param2, param3, param4])); - if (!_memoizationTable.containsKey(key)) { - _memoizationTable[key] = f(param1, param2, param3, param4); - } - return _memoizationTable[key]; + _MemoKey key = new _MemoKey(f, new HashableList([param1, param2, param3, param4])); + return _getOrUpdateCache(() => f(param1, param2, param3, param4), key); } /// Calls and caches the return value of [f]([param1], [param2], [param3], /// [param4], [param5]) if not in the cache, then returns the cached value of [f]( /// [param1], [param2], [param3], [param4], [param5]). R memoized5(R Function(A, B, C, D, E) f, A param1, B param2, C param3, D param4, E param5) { - Tuple2 key = new Tuple2(f, new HashableList([param1, param2, param3, param4, param5])); - if (!_memoizationTable.containsKey(key)) { - _memoizationTable[key] = f(param1, param2, param3, param4, param5); - } - return _memoizationTable[key]; + _MemoKey key = new _MemoKey(f, new HashableList([param1, param2, param3, param4, param5])); + return _getOrUpdateCache(() => f(param1, param2, param3, param4, param5), key); } /// Calls and caches the return value of [f]([param1], [param2], [param3], /// [param4], [param5], [param6]) if not in the cache, then returns the cached /// value of [f]([param1], [param2], [param3], [param4], [param5], [param6]). R memoized6(R Function(A, B, C, D, E, F) f, A param1, B param2, C param3, D param4, E param5, F param6) { - Tuple2 key = new Tuple2(f, new HashableList([param1, param2, param3, param4, param5, param6])); - if (!_memoizationTable.containsKey(key)) { - _memoizationTable[key] = f(param1, param2, param3, param4, param5, param6); - } - return _memoizationTable[key]; + _MemoKey key = new _MemoKey(f, new HashableList([param1, param2, param3, param4, param5, param6])); + return _getOrUpdateCache(() => f(param1, param2, param3, param4, param5, param6), key); } /// Calls and caches the return value of [f]([param1], [param2], [param3], @@ -282,11 +273,8 @@ class MethodMemoizer { /// the cached value of [f]([param1], [param2], [param3], [param4], [param5], /// [param6], [param7]). R memoized7(R Function(A, B, C, D, E, F, G) f, A param1, B param2, C param3, D param4, E param5, F param6, G param7) { - Tuple2 key = new Tuple2(f, new HashableList([param1, param2, param3, param4, param5, param6, param7])); - if (!_memoizationTable.containsKey(key)) { - _memoizationTable[key] = f(param1, param2, param3, param4, param5, param6, param7); - } - return _memoizationTable[key]; + _MemoKey key = new _MemoKey(f, new HashableList([param1, param2, param3, param4, param5, param6, param7])); + return _getOrUpdateCache(() => f(param1, param2, param3, param4, param5, param6, param7), key); } /// Calls and caches the return value of [f]([param1], [param2], [param3], @@ -294,10 +282,7 @@ class MethodMemoizer { /// then returns the cached value of [f]([param1], [param2], [param3], /// [param4], [param5], [param6], [param7], [param8]). R memoized8(R Function(A, B, C, D, E, F, G, H) f, A param1, B param2, C param3, D param4, E param5, F param6, G param7, H param8) { - Tuple2 key = new Tuple2(f, new HashableList([param1, param2, param3, param4, param5, param6, param7, param8])); - if (!_memoizationTable.containsKey(key)) { - _memoizationTable[key] = f(param1, param2, param3, param4, param5, param6, param7, param8); - } - return _memoizationTable[key]; + _MemoKey key = new _MemoKey(f, new HashableList([param1, param2, param3, param4, param5, param6, param7, param8])); + return _getOrUpdateCache(() => f(param1, param2, param3, param4, param5, param6, param7, param8), key); } } \ No newline at end of file From e3b9a91c1cfb96391af1ec90a918fcd3640b934c Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Tue, 12 Dec 2017 14:00:26 -0800 Subject: [PATCH 03/11] One more tweak --- lib/src/model_utils.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/model_utils.dart b/lib/src/model_utils.dart index 31c48d6314..16c8c2caa4 100644 --- a/lib/src/model_utils.dart +++ b/lib/src/model_utils.dart @@ -219,7 +219,7 @@ class MethodMemoizer { /// returns the cached value of [f](). R memoized(Function f) { _MemoKey key = new _MemoKey(f, new HashableList([])); - return _getOrUpdateCache(() => f(), key); + return _getOrUpdateCache(f, key); } /// Calls and caches the return value of [f]([param1]) if not in the cache, then From f583d2ec49dca77c396b11c8fbef013c0999fbb0 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Tue, 12 Dec 2017 14:02:57 -0800 Subject: [PATCH 04/11] dartfmt --- lib/src/model_utils.dart | 63 +++++++++++----- test/model_utils_test.dart | 144 +++++++++++++++++++++++++++---------- 2 files changed, 152 insertions(+), 55 deletions(-) diff --git a/lib/src/model_utils.dart b/lib/src/model_utils.dart index 16c8c2caa4..929ac4b904 100644 --- a/lib/src/model_utils.dart +++ b/lib/src/model_utils.dart @@ -176,7 +176,7 @@ class HashableList extends UnmodifiableListView { HashableList(Iterable iterable) : super(iterable); @override - bool operator==(other) { + bool operator ==(other) { if (this.length == other.length) { for (var index = 0; index < length; ++index) { if (this[index] != other[index]) return false; @@ -205,7 +205,9 @@ class MethodMemoizer { } /// Reset the memoization table, forcing calls of the underlying functions. - void invalidateMemos() { _memoizationTable = new Map(); } + void invalidateMemos() { + _memoizationTable = new Map(); + } // Never write this if statement again. R _getOrUpdateCache(R Function() f, _MemoKey key) { @@ -247,42 +249,69 @@ class MethodMemoizer { /// Calls and caches the return value of [f]([param1], [param2], [param3], /// [param4]) if not in the cache, then returns the cached value of /// [f]([param1], [param2], [param3], [param4]). - R memoized4(R Function(A, B, C, D) f, A param1, B param2, C param3, D param4) { - _MemoKey key = new _MemoKey(f, new HashableList([param1, param2, param3, param4])); + R memoized4( + R Function(A, B, C, D) f, A param1, B param2, C param3, D param4) { + _MemoKey key = + new _MemoKey(f, new HashableList([param1, param2, param3, param4])); return _getOrUpdateCache(() => f(param1, param2, param3, param4), key); } /// Calls and caches the return value of [f]([param1], [param2], [param3], /// [param4], [param5]) if not in the cache, then returns the cached value of [f]( /// [param1], [param2], [param3], [param4], [param5]). - R memoized5(R Function(A, B, C, D, E) f, A param1, B param2, C param3, D param4, E param5) { - _MemoKey key = new _MemoKey(f, new HashableList([param1, param2, param3, param4, param5])); - return _getOrUpdateCache(() => f(param1, param2, param3, param4, param5), key); + R memoized5(R Function(A, B, C, D, E) f, A param1, B param2, + C param3, D param4, E param5) { + _MemoKey key = new _MemoKey( + f, new HashableList([param1, param2, param3, param4, param5])); + return _getOrUpdateCache( + () => f(param1, param2, param3, param4, param5), key); } /// Calls and caches the return value of [f]([param1], [param2], [param3], /// [param4], [param5], [param6]) if not in the cache, then returns the cached /// value of [f]([param1], [param2], [param3], [param4], [param5], [param6]). - R memoized6(R Function(A, B, C, D, E, F) f, A param1, B param2, C param3, D param4, E param5, F param6) { - _MemoKey key = new _MemoKey(f, new HashableList([param1, param2, param3, param4, param5, param6])); - return _getOrUpdateCache(() => f(param1, param2, param3, param4, param5, param6), key); + R memoized6(R Function(A, B, C, D, E, F) f, A param1, + B param2, C param3, D param4, E param5, F param6) { + _MemoKey key = new _MemoKey( + f, new HashableList([param1, param2, param3, param4, param5, param6])); + return _getOrUpdateCache( + () => f(param1, param2, param3, param4, param5, param6), key); } /// Calls and caches the return value of [f]([param1], [param2], [param3], /// [param4], [param5], [param6], [param7]) if not in the cache, then returns /// the cached value of [f]([param1], [param2], [param3], [param4], [param5], /// [param6], [param7]). - R memoized7(R Function(A, B, C, D, E, F, G) f, A param1, B param2, C param3, D param4, E param5, F param6, G param7) { - _MemoKey key = new _MemoKey(f, new HashableList([param1, param2, param3, param4, param5, param6, param7])); - return _getOrUpdateCache(() => f(param1, param2, param3, param4, param5, param6, param7), key); + R memoized7(R Function(A, B, C, D, E, F, G) f, + A param1, B param2, C param3, D param4, E param5, F param6, G param7) { + _MemoKey key = new _MemoKey( + f, + new HashableList( + [param1, param2, param3, param4, param5, param6, param7])); + return _getOrUpdateCache( + () => f(param1, param2, param3, param4, param5, param6, param7), key); } /// Calls and caches the return value of [f]([param1], [param2], [param3], /// [param4], [param5], [param6], [param7], [param8]) if not in the cache, /// then returns the cached value of [f]([param1], [param2], [param3], /// [param4], [param5], [param6], [param7], [param8]). - R memoized8(R Function(A, B, C, D, E, F, G, H) f, A param1, B param2, C param3, D param4, E param5, F param6, G param7, H param8) { - _MemoKey key = new _MemoKey(f, new HashableList([param1, param2, param3, param4, param5, param6, param7, param8])); - return _getOrUpdateCache(() => f(param1, param2, param3, param4, param5, param6, param7, param8), key); + R memoized8( + R Function(A, B, C, D, E, F, G, H) f, + A param1, + B param2, + C param3, + D param4, + E param5, + F param6, + G param7, + H param8) { + _MemoKey key = new _MemoKey( + f, + new HashableList( + [param1, param2, param3, param4, param5, param6, param7, param8])); + return _getOrUpdateCache( + () => f(param1, param2, param3, param4, param5, param6, param7, param8), + key); } -} \ No newline at end of file +} diff --git a/test/model_utils_test.dart b/test/model_utils_test.dart index cb87b2d16d..a992ea02c5 100644 --- a/test/model_utils_test.dart +++ b/test/model_utils_test.dart @@ -11,32 +11,77 @@ class MemoizerUser extends MethodMemoizer { int foo = 0; // These are actually not things you would ordinarily memoize, because // they change. But they are useful for testing. - int _toMemoize() { return foo++; } + int _toMemoize() { + return foo++; + } + int get toMemoize => memoized(_toMemoize); String _memoizedParameter1(String param) => "${foo++} ${param}"; - String memoizedParameter1(String param) => memoized1(_memoizedParameter1, param); - - String _memoizedParameter2(String param, String param2) => "${foo++} ${param} ${param2}"; - String memoizedParameter2(String param, String param2) => memoized2(_memoizedParameter2, param, param2); - - String _memoizedParameter3(String param, String param2, String param3) => "${foo++} ${param} ${param2} ${param3}"; - String memoizedParameter3(String param, String param2, String param3) => memoized3(_memoizedParameter3, param, param2, param3); - - String _memoizedParameter4(String param, String param2, String param3, String param4) => "${foo++} ${param} ${param2} ${param3} ${param4}"; - String memoizedParameter4(String param, String param2, String param3, String param4) => memoized4(_memoizedParameter4, param, param2, param3, param4); - - String _memoizedParameter5(String param, String param2, String param3, String param4, String param5) => "${foo++} ${param} ${param2} ${param3} ${param4} ${param5}"; - String memoizedParameter5(String param, String param2, String param3, String param4, String param5) => memoized5(_memoizedParameter5, param, param2, param3, param4, param5); - - String _memoizedParameter6(String param, String param2, String param3, String param4, String param5, String param6) => "${foo++} ${param} ${param2} ${param3} ${param4} ${param5} ${param6}"; - String memoizedParameter6(String param, String param2, String param3, String param4, String param5, String param6) => memoized6(_memoizedParameter6, param, param2, param3, param4, param5, param6); - - String _memoizedParameter7(String param, String param2, String param3, String param4, String param5, String param6, String param7) => "${foo++} ${param} ${param2} ${param3} ${param4} ${param5} ${param6} ${param7}"; - String memoizedParameter7(String param, String param2, String param3, String param4, String param5, String param6, String param7) => memoized7(_memoizedParameter7, param, param2, param3, param4, param5, param6, param7); - - String _memoizedParameter8(String param, String param2, String param3, String param4, String param5, String param6, String param7, String param8) => "${foo++} ${param} ${param2} ${param3} ${param4} ${param5} ${param6} ${param7} ${param8}"; - String memoizedParameter8(String param, String param2, String param3, String param4, String param5, String param6, String param7, String param8) => memoized8(_memoizedParameter8, param, param2, param3, param4, param5, param6, param7, param8); + String memoizedParameter1(String param) => + memoized1(_memoizedParameter1, param); + + String _memoizedParameter2(String param, String param2) => + "${foo++} ${param} ${param2}"; + String memoizedParameter2(String param, String param2) => + memoized2(_memoizedParameter2, param, param2); + + String _memoizedParameter3(String param, String param2, String param3) => + "${foo++} ${param} ${param2} ${param3}"; + String memoizedParameter3(String param, String param2, String param3) => + memoized3(_memoizedParameter3, param, param2, param3); + + String _memoizedParameter4( + String param, String param2, String param3, String param4) => + "${foo++} ${param} ${param2} ${param3} ${param4}"; + String memoizedParameter4( + String param, String param2, String param3, String param4) => + memoized4(_memoizedParameter4, param, param2, param3, param4); + + String _memoizedParameter5(String param, String param2, String param3, + String param4, String param5) => + "${foo++} ${param} ${param2} ${param3} ${param4} ${param5}"; + String memoizedParameter5(String param, String param2, String param3, + String param4, String param5) => + memoized5(_memoizedParameter5, param, param2, param3, param4, param5); + + String _memoizedParameter6(String param, String param2, String param3, + String param4, String param5, String param6) => + "${foo++} ${param} ${param2} ${param3} ${param4} ${param5} ${param6}"; + String memoizedParameter6(String param, String param2, String param3, + String param4, String param5, String param6) => + memoized6( + _memoizedParameter6, param, param2, param3, param4, param5, param6); + + String _memoizedParameter7(String param, String param2, String param3, + String param4, String param5, String param6, String param7) => + "${foo++} ${param} ${param2} ${param3} ${param4} ${param5} ${param6} ${param7}"; + String memoizedParameter7(String param, String param2, String param3, + String param4, String param5, String param6, String param7) => + memoized7(_memoizedParameter7, param, param2, param3, param4, param5, + param6, param7); + + String _memoizedParameter8( + String param, + String param2, + String param3, + String param4, + String param5, + String param6, + String param7, + String param8) => + "${foo++} ${param} ${param2} ${param3} ${param4} ${param5} ${param6} ${param7} ${param8}"; + String memoizedParameter8( + String param, + String param2, + String param3, + String param4, + String param5, + String param6, + String param7, + String param8) => + memoized8(_memoizedParameter8, param, param2, param3, param4, param5, + param6, param7, param8); } void main() { @@ -96,32 +141,55 @@ void main() { test('memoization of a method with parameter', () { var m = new MemoizerUser(); - expect(m.memoizedParameter1("hello"), equals("0 hello"), reason: "initialization problem"); - expect(m.memoizedParameter1("hello"), equals("0 hello"), reason: "failed to memoize"); + expect(m.memoizedParameter1("hello"), equals("0 hello"), + reason: "initialization problem"); + expect(m.memoizedParameter1("hello"), equals("0 hello"), + reason: "failed to memoize"); expect(m.memoizedParameter1("goodbye"), equals("1 goodbye")); expect(m.memoizedParameter1("something"), equals("2 something")); m.invalidateMemos(); - expect(m.memoizedParameter1("hello"), equals("3 hello"), reason: "failed to invalidate"); + expect(m.memoizedParameter1("hello"), equals("3 hello"), + reason: "failed to invalidate"); }); test('memoization of many parameters', () { var m = new MemoizerUser(); expect(m.memoizedParameter1("hello"), equals("0 hello")); expect(m.memoizedParameter2("hello", "obi"), equals("1 hello obi")); - expect(m.memoizedParameter3("hello", "obi", "wan"), equals("2 hello obi wan")); - expect(m.memoizedParameter4("hello", "obi", "wan", "how"), equals("3 hello obi wan how")); - expect(m.memoizedParameter5("hello", "obi", "wan", "how", "are"), equals("4 hello obi wan how are")); - expect(m.memoizedParameter6("hello", "obi", "wan", "how", "are", "you"), equals("5 hello obi wan how are you")); - expect(m.memoizedParameter7("hello", "obi", "wan", "how", "are", "you", "doing"), equals("6 hello obi wan how are you doing")); - expect(m.memoizedParameter8("hello", "obi", "wan", "how", "are", "you", "doing", "today"), equals("7 hello obi wan how are you doing today")); + expect(m.memoizedParameter3("hello", "obi", "wan"), + equals("2 hello obi wan")); + expect(m.memoizedParameter4("hello", "obi", "wan", "how"), + equals("3 hello obi wan how")); + expect(m.memoizedParameter5("hello", "obi", "wan", "how", "are"), + equals("4 hello obi wan how are")); + expect(m.memoizedParameter6("hello", "obi", "wan", "how", "are", "you"), + equals("5 hello obi wan how are you")); + expect( + m.memoizedParameter7( + "hello", "obi", "wan", "how", "are", "you", "doing"), + equals("6 hello obi wan how are you doing")); + expect( + m.memoizedParameter8( + "hello", "obi", "wan", "how", "are", "you", "doing", "today"), + equals("7 hello obi wan how are you doing today")); expect(m.memoizedParameter1("hello"), equals("0 hello")); expect(m.memoizedParameter2("hello", "obi"), equals("1 hello obi")); - expect(m.memoizedParameter3("hello", "obi", "wan"), equals("2 hello obi wan")); - expect(m.memoizedParameter4("hello", "obi", "wan", "how"), equals("3 hello obi wan how")); - expect(m.memoizedParameter5("hello", "obi", "wan", "how", "are"), equals("4 hello obi wan how are")); - expect(m.memoizedParameter6("hello", "obi", "wan", "how", "are", "you"), equals("5 hello obi wan how are you")); - expect(m.memoizedParameter7("hello", "obi", "wan", "how", "are", "you", "doing"), equals("6 hello obi wan how are you doing")); - expect(m.memoizedParameter8("hello", "obi", "wan", "how", "are", "you", "doing", "today"), equals("7 hello obi wan how are you doing today")); + expect(m.memoizedParameter3("hello", "obi", "wan"), + equals("2 hello obi wan")); + expect(m.memoizedParameter4("hello", "obi", "wan", "how"), + equals("3 hello obi wan how")); + expect(m.memoizedParameter5("hello", "obi", "wan", "how", "are"), + equals("4 hello obi wan how are")); + expect(m.memoizedParameter6("hello", "obi", "wan", "how", "are", "you"), + equals("5 hello obi wan how are you")); + expect( + m.memoizedParameter7( + "hello", "obi", "wan", "how", "are", "you", "doing"), + equals("6 hello obi wan how are you doing")); + expect( + m.memoizedParameter8( + "hello", "obi", "wan", "how", "are", "you", "doing", "today"), + equals("7 hello obi wan how are you doing today")); }); }); } From ac450e6a958e054029a8b3ef086a543bbb9df8e5 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Tue, 12 Dec 2017 14:20:43 -0800 Subject: [PATCH 05/11] Add the motivating case --- lib/src/model_utils.dart | 5 +++-- test/model_utils_test.dart | 2 +- tool/grind.dart | 30 ++++++++---------------------- 3 files changed, 12 insertions(+), 25 deletions(-) diff --git a/lib/src/model_utils.dart b/lib/src/model_utils.dart index 929ac4b904..bca64addaa 100644 --- a/lib/src/model_utils.dart +++ b/lib/src/model_utils.dart @@ -190,17 +190,18 @@ class HashableList extends UnmodifiableListView { get hashCode => hashObjects(this); } +/// A type alias for [Tuple2]``. class _MemoKey extends Tuple2 { _MemoKey(Function f, HashableList l) : super(f, l) {} } /// Extend or use as a mixin to track object-specific cached values, or /// instantiate directly to track other values. -class MethodMemoizer { +class Memoizer { /// Map of a function and its positional parameters (if any), to a value. Map<_MemoKey, dynamic> _memoizationTable; - MethodMemoizer() { + Memoizer() { invalidateMemos(); } diff --git a/test/model_utils_test.dart b/test/model_utils_test.dart index a992ea02c5..9fe5c42a51 100644 --- a/test/model_utils_test.dart +++ b/test/model_utils_test.dart @@ -7,7 +7,7 @@ library dartdoc.model_utils_test; import 'package:dartdoc/src/model_utils.dart'; import 'package:test/test.dart'; -class MemoizerUser extends MethodMemoizer { +class MemoizerUser extends Memoizer { int foo = 0; // These are actually not things you would ordinarily memoize, because // they change. But they are useful for testing. diff --git a/tool/grind.dart b/tool/grind.dart index 3601561f9c..3b7d53edb2 100644 --- a/tool/grind.dart +++ b/tool/grind.dart @@ -7,35 +7,21 @@ import 'dart:convert'; import 'dart:io' hide ProcessException; import 'package:dartdoc/src/io_utils.dart'; +import 'package:dartdoc/src/model_utils.dart'; import 'package:grinder/grinder.dart'; import 'package:path/path.dart' as path; import 'package:yaml/yaml.dart' as yaml; main([List args]) => grind(args); -Directory _dartdocDocsDir; -Directory get dartdocDocsDir { - if (_dartdocDocsDir == null) { - _dartdocDocsDir = Directory.systemTemp.createTempSync('dartdoc'); - } - return _dartdocDocsDir; -} +final Memoizer tempdirsCache = new Memoizer(); -Directory _sdkDocsDir; -Directory get sdkDocsDir { - if (_sdkDocsDir == null) { - _sdkDocsDir = Directory.systemTemp.createTempSync('sdkdocs'); - } - return _sdkDocsDir; -} - -Directory _flutterDir; -Directory get flutterDir { - if (_flutterDir == null) { - _flutterDir = Directory.systemTemp.createTempSync('flutter'); - } - return _flutterDir; -} +Directory get dartdocDocsDir => + tempdirsCache.memoized1(Directory.systemTemp.createTempSync, 'dartdoc'); +Directory get sdkDocsDir => + tempdirsCache.memoized1(Directory.systemTemp.createTempSync, 'sdkdocs'); +Directory get flutterDir => + tempdirsCache.memoized1(Directory.systemTemp.createTempSync, 'flutter'); final Directory flutterDirDevTools = new Directory(path.join(flutterDir.path, 'dev', 'tools')); From afe4aa6335162060d3f5db209742e5f4ac096e06 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Tue, 12 Dec 2017 15:13:33 -0800 Subject: [PATCH 06/11] systemTemp was not a constant --- tool/grind.dart | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tool/grind.dart b/tool/grind.dart index 3b7d53edb2..5429089ed8 100644 --- a/tool/grind.dart +++ b/tool/grind.dart @@ -14,14 +14,16 @@ import 'package:yaml/yaml.dart' as yaml; main([List args]) => grind(args); +// Directory.systemTemp is not a constant. So wrap it. +Directory createTempSync(String prefix) => + Directory.systemTemp.createTempSync(prefix); + final Memoizer tempdirsCache = new Memoizer(); Directory get dartdocDocsDir => - tempdirsCache.memoized1(Directory.systemTemp.createTempSync, 'dartdoc'); -Directory get sdkDocsDir => - tempdirsCache.memoized1(Directory.systemTemp.createTempSync, 'sdkdocs'); -Directory get flutterDir => - tempdirsCache.memoized1(Directory.systemTemp.createTempSync, 'flutter'); + tempdirsCache.memoized1(createTempSync, 'dartdoc'); +Directory get sdkDocsDir => tempdirsCache.memoized1(createTempSync, 'sdkdocs'); +Directory get flutterDir => tempdirsCache.memoized1(createTempSync, 'flutter'); final Directory flutterDirDevTools = new Directory(path.join(flutterDir.path, 'dev', 'tools')); @@ -130,6 +132,8 @@ analyze() async { @Depends(analyze, test, testDartdoc) buildbot() => null; +void anOrdinaryFunction() {} + @Task('Generate docs for the Dart SDK') Future buildSdkDocs() async { log('building SDK docs'); From 5f66b7abb4a2d55b41e8d0b0e6960cfe8bd12d30 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Tue, 12 Dec 2017 15:16:10 -0800 Subject: [PATCH 07/11] Cleanup --- tool/grind.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/tool/grind.dart b/tool/grind.dart index 5429089ed8..d84e372b72 100644 --- a/tool/grind.dart +++ b/tool/grind.dart @@ -132,8 +132,6 @@ analyze() async { @Depends(analyze, test, testDartdoc) buildbot() => null; -void anOrdinaryFunction() {} - @Task('Generate docs for the Dart SDK') Future buildSdkDocs() async { log('building SDK docs'); From 5a22c16f0021dd9a9ccca5fd04b5cdcde456a66b Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Wed, 13 Dec 2017 09:21:15 -0800 Subject: [PATCH 08/11] Review comments --- lib/src/model_utils.dart | 80 ++++++++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 32 deletions(-) diff --git a/lib/src/model_utils.dart b/lib/src/model_utils.dart index bca64addaa..2aed1855ef 100644 --- a/lib/src/model_utils.dart +++ b/lib/src/model_utils.dart @@ -14,7 +14,6 @@ import 'package:analyzer/src/generated/sdk.dart'; import 'package:analyzer/src/generated/source_io.dart'; import 'package:dartdoc/src/model.dart'; import 'package:quiver_hashcode/hashcode.dart'; -import 'package:tuple/tuple.dart'; import 'config.dart'; @@ -172,16 +171,18 @@ 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 extends UnmodifiableListView { + _HashableList(Iterable iterable) : super(iterable); @override bool operator ==(other) { - if (this.length == other.length) { - for (var index = 0; index < length; ++index) { - if (this[index] != other[index]) return false; + if (other is _HashableList) { + if (this.length == other.length) { + for (var index = 0; index < length; ++index) { + if (this[index] != other[index]) return false; + } + return true; } - return true; } return false; } @@ -190,16 +191,35 @@ class HashableList extends UnmodifiableListView { get hashCode => hashObjects(this); } -/// A type alias for [Tuple2]``. -class _MemoKey extends Tuple2 { - _MemoKey(Function f, HashableList l) : super(f, l) {} -} - /// Extend or use as a mixin to track object-specific cached values, or /// instantiate directly to track other values. +/// +/// For all methods in this class, the parameter [f] must be a tear-off method +/// or top level function (not an inline closure) for memoization to work. +/// [Memoizer] depends on the equality operator on the given function to detect +/// when we are calling the same function. +/// +/// Use: +/// +/// ```dart +/// String aTestFunction(String greeting, String name) => "${greeting}, ${name}"; +/// int aSlowFunction() { doSome(); return expensiveCalculations(); } +/// +/// myMemoizer.memoized2(aTestFunction, "Hello, "world"); +/// myMemoizer.memoized(aSlowFunction); +/// ``` +/// +/// *Not*: +/// +/// ```dart +/// String aTestFunction(String greeting, String name) => "${greeting}, ${name}"; +/// +/// myMemoizer.memoized2((a, b) => aTestFunction(a, b), "Hello", "world"); +/// myMemoizer.memoized(() => aSlowFunction());; +/// ``` class Memoizer { /// Map of a function and its positional parameters (if any), to a value. - Map<_MemoKey, dynamic> _memoizationTable; + Map<_HashableList, dynamic> _memoizationTable; Memoizer() { invalidateMemos(); @@ -211,7 +231,7 @@ class Memoizer { } // Never write this if statement again. - R _getOrUpdateCache(R Function() f, _MemoKey key) { + R _getOrUpdateCache(R Function() f, _HashableList key) { if (!_memoizationTable.containsKey(key)) { _memoizationTable[key] = f(); } @@ -220,22 +240,24 @@ 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) { - _MemoKey key = new _MemoKey(f, new HashableList([])); + _HashableList key = new _HashableList([f]); return _getOrUpdateCache(f, key); } /// Calls and caches the return value of [f]([param1]) if not in the cache, then /// returns the cached value of [f]([param1]). R memoized1(R Function(A) f, A param1) { - _MemoKey key = new _MemoKey(f, new HashableList([param1])); + _HashableList key = new _HashableList([f, param1]); return _getOrUpdateCache(() => f(param1), key); } /// Calls and caches the return value of [f]([param1], [param2]) if not in the /// cache, then returns the cached value of [f]([param1], [param2]). R memoized2(R Function(A, B) f, A param1, B param2) { - _MemoKey key = new _MemoKey(f, new HashableList([param1, param2])); + _HashableList key = new _HashableList([f, param1, param2]); return _getOrUpdateCache(() => f(param1, param2), key); } @@ -243,7 +265,7 @@ class Memoizer { /// not in the cache, then returns the cached value of [f]([param1], /// [param2], [param3]). R memoized3(R Function(A, B, C) f, A param1, B param2, C param3) { - _MemoKey key = new _MemoKey(f, new HashableList([param1, param2, param3])); + _HashableList key = new _HashableList([f, param1, param2, param3]); return _getOrUpdateCache(() => f(param1, param2, param3), key); } @@ -252,8 +274,8 @@ class Memoizer { /// [f]([param1], [param2], [param3], [param4]). R memoized4( R Function(A, B, C, D) f, A param1, B param2, C param3, D param4) { - _MemoKey key = - new _MemoKey(f, new HashableList([param1, param2, param3, param4])); + _HashableList key = + new _HashableList([f, param1, param2, param3, param4]); return _getOrUpdateCache(() => f(param1, param2, param3, param4), key); } @@ -262,8 +284,7 @@ class Memoizer { /// [param1], [param2], [param3], [param4], [param5]). R memoized5(R Function(A, B, C, D, E) f, A param1, B param2, C param3, D param4, E param5) { - _MemoKey key = new _MemoKey( - f, new HashableList([param1, param2, param3, param4, param5])); + _HashableList key = new _HashableList([f, param1, param2, param3, param4, param5]); return _getOrUpdateCache( () => f(param1, param2, param3, param4, param5), key); } @@ -273,8 +294,7 @@ class Memoizer { /// value of [f]([param1], [param2], [param3], [param4], [param5], [param6]). R memoized6(R Function(A, B, C, D, E, F) f, A param1, B param2, C param3, D param4, E param5, F param6) { - _MemoKey key = new _MemoKey( - f, new HashableList([param1, param2, param3, param4, param5, param6])); + _HashableList key = new _HashableList([f, param1, param2, param3, param4, param5, param6]); return _getOrUpdateCache( () => f(param1, param2, param3, param4, param5, param6), key); } @@ -285,10 +305,8 @@ class Memoizer { /// [param6], [param7]). R memoized7(R Function(A, B, C, D, E, F, G) f, A param1, B param2, C param3, D param4, E param5, F param6, G param7) { - _MemoKey key = new _MemoKey( - f, - new HashableList( - [param1, param2, param3, param4, param5, param6, param7])); + _HashableList key = new _HashableList( + [f, param1, param2, param3, param4, param5, param6, param7]); return _getOrUpdateCache( () => f(param1, param2, param3, param4, param5, param6, param7), key); } @@ -307,10 +325,8 @@ class Memoizer { F param6, G param7, H param8) { - _MemoKey key = new _MemoKey( - f, - new HashableList( - [param1, param2, param3, param4, param5, param6, param7, param8])); + _HashableList key = new _HashableList( + [f, param1, param2, param3, param4, param5, param6, param7, param8]); return _getOrUpdateCache( () => f(param1, param2, param3, param4, param5, param6, param7, param8), key); From a05f3954915f586a0183be9f9b30bc19638aaca6 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Wed, 13 Dec 2017 09:21:43 -0800 Subject: [PATCH 09/11] dartfmt --- lib/src/model_utils.dart | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/src/model_utils.dart b/lib/src/model_utils.dart index 2aed1855ef..983d06c3e2 100644 --- a/lib/src/model_utils.dart +++ b/lib/src/model_utils.dart @@ -243,21 +243,21 @@ class Memoizer { /// R memoized(Function f) { - _HashableList key = new _HashableList([f]); + _HashableList key = new _HashableList([f]); return _getOrUpdateCache(f, key); } /// Calls and caches the return value of [f]([param1]) if not in the cache, then /// returns the cached value of [f]([param1]). R memoized1(R Function(A) f, A param1) { - _HashableList key = new _HashableList([f, param1]); + _HashableList key = new _HashableList([f, param1]); return _getOrUpdateCache(() => f(param1), key); } /// Calls and caches the return value of [f]([param1], [param2]) if not in the /// cache, then returns the cached value of [f]([param1], [param2]). R memoized2(R Function(A, B) f, A param1, B param2) { - _HashableList key = new _HashableList([f, param1, param2]); + _HashableList key = new _HashableList([f, param1, param2]); return _getOrUpdateCache(() => f(param1, param2), key); } @@ -265,7 +265,7 @@ class Memoizer { /// not in the cache, then returns the cached value of [f]([param1], /// [param2], [param3]). R memoized3(R Function(A, B, C) f, A param1, B param2, C param3) { - _HashableList key = new _HashableList([f, param1, param2, param3]); + _HashableList key = new _HashableList([f, param1, param2, param3]); return _getOrUpdateCache(() => f(param1, param2, param3), key); } @@ -274,8 +274,7 @@ class Memoizer { /// [f]([param1], [param2], [param3], [param4]). R memoized4( R Function(A, B, C, D) f, A param1, B param2, C param3, D param4) { - _HashableList key = - new _HashableList([f, param1, param2, param3, param4]); + _HashableList key = new _HashableList([f, param1, param2, param3, param4]); return _getOrUpdateCache(() => f(param1, param2, param3, param4), key); } @@ -284,7 +283,8 @@ class Memoizer { /// [param1], [param2], [param3], [param4], [param5]). R memoized5(R Function(A, B, C, D, E) f, A param1, B param2, C param3, D param4, E param5) { - _HashableList key = new _HashableList([f, param1, param2, param3, param4, param5]); + _HashableList key = + new _HashableList([f, param1, param2, param3, param4, param5]); return _getOrUpdateCache( () => f(param1, param2, param3, param4, param5), key); } @@ -294,7 +294,8 @@ class Memoizer { /// value of [f]([param1], [param2], [param3], [param4], [param5], [param6]). R memoized6(R Function(A, B, C, D, E, F) f, A param1, B param2, C param3, D param4, E param5, F param6) { - _HashableList key = new _HashableList([f, param1, param2, param3, param4, param5, param6]); + _HashableList key = + new _HashableList([f, param1, param2, param3, param4, param5, param6]); return _getOrUpdateCache( () => f(param1, param2, param3, param4, param5, param6), key); } @@ -306,7 +307,7 @@ class Memoizer { R memoized7(R Function(A, B, C, D, E, F, G) f, A param1, B param2, C param3, D param4, E param5, F param6, G param7) { _HashableList key = new _HashableList( - [f, param1, param2, param3, param4, param5, param6, param7]); + [f, param1, param2, param3, param4, param5, param6, param7]); return _getOrUpdateCache( () => f(param1, param2, param3, param4, param5, param6, param7), key); } @@ -326,7 +327,7 @@ class Memoizer { G param7, H param8) { _HashableList key = new _HashableList( - [f, param1, param2, param3, param4, param5, param6, param7, param8]); + [f, param1, param2, param3, param4, param5, param6, param7, param8]); return _getOrUpdateCache( () => f(param1, param2, param3, param4, param5, param6, param7, param8), key); From bb07ee3136fedd8cab663a41c43ccf100c99d3d5 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Wed, 13 Dec 2017 15:24:54 -0800 Subject: [PATCH 10/11] Eliminate the if statement altogether. --- lib/src/model_utils.dart | 37 +++++++++++++------------------------ pubspec.lock | 2 +- 2 files changed, 14 insertions(+), 25 deletions(-) diff --git a/lib/src/model_utils.dart b/lib/src/model_utils.dart index 983d06c3e2..c997032549 100644 --- a/lib/src/model_utils.dart +++ b/lib/src/model_utils.dart @@ -230,35 +230,25 @@ class Memoizer { _memoizationTable = new Map(); } - // Never write this if statement again. - R _getOrUpdateCache(R Function() f, _HashableList key) { - if (!_memoizationTable.containsKey(key)) { - _memoizationTable[key] = f(); - } - return _memoizationTable[key]; - } - /// 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]); - return _getOrUpdateCache(f, key); + return _memoizationTable.putIfAbsent(key, f); } /// Calls and caches the return value of [f]([param1]) if not in the cache, then /// returns the cached value of [f]([param1]). R memoized1(R Function(A) f, A param1) { _HashableList key = new _HashableList([f, param1]); - return _getOrUpdateCache(() => f(param1), key); + return _memoizationTable.putIfAbsent(key, () => f(param1)); } /// Calls and caches the return value of [f]([param1], [param2]) if not in the /// cache, then returns the cached value of [f]([param1], [param2]). R memoized2(R Function(A, B) f, A param1, B param2) { _HashableList key = new _HashableList([f, param1, param2]); - return _getOrUpdateCache(() => f(param1, param2), key); + return _memoizationTable.putIfAbsent(key, () => f(param1, param2)); } /// Calls and caches the return value of [f]([param1], [param2], [param3]) if @@ -266,7 +256,7 @@ class Memoizer { /// [param2], [param3]). R memoized3(R Function(A, B, C) f, A param1, B param2, C param3) { _HashableList key = new _HashableList([f, param1, param2, param3]); - return _getOrUpdateCache(() => f(param1, param2, param3), key); + return _memoizationTable.putIfAbsent(key, () => f(param1, param2, param3)); } /// Calls and caches the return value of [f]([param1], [param2], [param3], @@ -275,7 +265,7 @@ class Memoizer { R memoized4( R Function(A, B, C, D) f, A param1, B param2, C param3, D param4) { _HashableList key = new _HashableList([f, param1, param2, param3, param4]); - return _getOrUpdateCache(() => f(param1, param2, param3, param4), key); + return _memoizationTable.putIfAbsent(key, () => f(param1, param2, param3, param4)); } /// Calls and caches the return value of [f]([param1], [param2], [param3], @@ -285,8 +275,8 @@ class Memoizer { C param3, D param4, E param5) { _HashableList key = new _HashableList([f, param1, param2, param3, param4, param5]); - return _getOrUpdateCache( - () => f(param1, param2, param3, param4, param5), key); + return _memoizationTable.putIfAbsent(key, + () => f(param1, param2, param3, param4, param5)); } /// Calls and caches the return value of [f]([param1], [param2], [param3], @@ -296,8 +286,8 @@ class Memoizer { B param2, C param3, D param4, E param5, F param6) { _HashableList key = new _HashableList([f, param1, param2, param3, param4, param5, param6]); - return _getOrUpdateCache( - () => f(param1, param2, param3, param4, param5, param6), key); + return _memoizationTable.putIfAbsent(key, + () => f(param1, param2, param3, param4, param5, param6)); } /// Calls and caches the return value of [f]([param1], [param2], [param3], @@ -308,8 +298,8 @@ class Memoizer { A param1, B param2, C param3, D param4, E param5, F param6, G param7) { _HashableList key = new _HashableList( [f, param1, param2, param3, param4, param5, param6, param7]); - return _getOrUpdateCache( - () => f(param1, param2, param3, param4, param5, param6, param7), key); + return _memoizationTable.putIfAbsent(key, + () => f(param1, param2, param3, param4, param5, param6, param7)); } /// Calls and caches the return value of [f]([param1], [param2], [param3], @@ -328,8 +318,7 @@ class Memoizer { H param8) { _HashableList key = new _HashableList( [f, param1, param2, param3, param4, param5, param6, param7, param8]); - return _getOrUpdateCache( - () => f(param1, param2, param3, param4, param5, param6, param7, param8), - key); + return _memoizationTable.putIfAbsent(key, + () => f(param1, param2, param3, param4, param5, param6, param7, param8)); } } diff --git a/pubspec.lock b/pubspec.lock index 566f015931..d505112a10 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -374,4 +374,4 @@ packages: source: hosted version: "2.1.13" sdks: - dart: ">=1.23.0 <=2.0.0-dev.10.0" + dart: ">=1.23.0 <=2.0.0-dev.12.0" From 3eb76c6bcfde97f3b4796baeeac4738ef64e5f39 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Wed, 13 Dec 2017 15:26:46 -0800 Subject: [PATCH 11/11] dartfmt --- lib/src/model_utils.dart | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/lib/src/model_utils.dart b/lib/src/model_utils.dart index c997032549..db2e211bf2 100644 --- a/lib/src/model_utils.dart +++ b/lib/src/model_utils.dart @@ -265,7 +265,8 @@ class Memoizer { R memoized4( R Function(A, B, C, D) f, A param1, B param2, C param3, D param4) { _HashableList key = new _HashableList([f, param1, param2, param3, param4]); - return _memoizationTable.putIfAbsent(key, () => f(param1, param2, param3, param4)); + return _memoizationTable.putIfAbsent( + key, () => f(param1, param2, param3, param4)); } /// Calls and caches the return value of [f]([param1], [param2], [param3], @@ -275,8 +276,8 @@ class Memoizer { C param3, D param4, E param5) { _HashableList key = new _HashableList([f, param1, param2, param3, param4, param5]); - return _memoizationTable.putIfAbsent(key, - () => f(param1, param2, param3, param4, param5)); + return _memoizationTable.putIfAbsent( + key, () => f(param1, param2, param3, param4, param5)); } /// Calls and caches the return value of [f]([param1], [param2], [param3], @@ -286,8 +287,8 @@ class Memoizer { B param2, C param3, D param4, E param5, F param6) { _HashableList key = new _HashableList([f, param1, param2, param3, param4, param5, param6]); - return _memoizationTable.putIfAbsent(key, - () => f(param1, param2, param3, param4, param5, param6)); + return _memoizationTable.putIfAbsent( + key, () => f(param1, param2, param3, param4, param5, param6)); } /// Calls and caches the return value of [f]([param1], [param2], [param3], @@ -298,8 +299,8 @@ class Memoizer { A param1, B param2, C param3, D param4, E param5, F param6, G param7) { _HashableList key = new _HashableList( [f, param1, param2, param3, param4, param5, param6, param7]); - return _memoizationTable.putIfAbsent(key, - () => f(param1, param2, param3, param4, param5, param6, param7)); + return _memoizationTable.putIfAbsent( + key, () => f(param1, param2, param3, param4, param5, param6, param7)); } /// Calls and caches the return value of [f]([param1], [param2], [param3], @@ -318,7 +319,9 @@ class Memoizer { H param8) { _HashableList key = new _HashableList( [f, param1, param2, param3, param4, param5, param6, param7, param8]); - return _memoizationTable.putIfAbsent(key, - () => f(param1, param2, param3, param4, param5, param6, param7, param8)); + return _memoizationTable.putIfAbsent( + key, + () => + f(param1, param2, param3, param4, param5, param6, param7, param8)); } }