From a857b4ab9a9c828708c4e7a5d03f1ea97ba782c4 Mon Sep 17 00:00:00 2001 From: Cameron Fischer Date: Sun, 6 Dec 2020 03:54:57 -0500 Subject: [PATCH] use a linked list for filter runs. (#5206) * Changed the filterrunprefixes to use LinkedList * Testing for Linked List * Finishing touches to LinkedList * Minor corrections to link-list coding style * Corrected for sneaky bug in linkedList --- core/modules/filterrunprefixes/all.js | 2 +- core/modules/filterrunprefixes/and.js | 6 +- core/modules/filterrunprefixes/else.js | 2 +- core/modules/filterrunprefixes/except.js | 2 +- core/modules/filterrunprefixes/filter.js | 4 +- .../modules/filterrunprefixes/intersection.js | 5 +- core/modules/filterrunprefixes/or.js | 2 +- core/modules/filterrunprefixes/reduce.js | 11 +- core/modules/filters.js | 4 +- core/modules/utils/linked-list.js | 118 ++++++++++++++++ .../test/tiddlers/tests/test-linked-list.js | 130 ++++++++++++++++++ 11 files changed, 268 insertions(+), 18 deletions(-) create mode 100644 core/modules/utils/linked-list.js create mode 100644 editions/test/tiddlers/tests/test-linked-list.js diff --git a/core/modules/filterrunprefixes/all.js b/core/modules/filterrunprefixes/all.js index 2e25bbc4d..652936de0 100644 --- a/core/modules/filterrunprefixes/all.js +++ b/core/modules/filterrunprefixes/all.js @@ -18,7 +18,7 @@ Export our filter prefix function */ exports.all = function(operationSubFunction) { return function(results,source,widget) { - Array.prototype.push.apply(results,operationSubFunction(source,widget)); + results.push.apply(results, operationSubFunction(source,widget)); }; }; diff --git a/core/modules/filterrunprefixes/and.js b/core/modules/filterrunprefixes/and.js index ad41c049c..309c228e6 100644 --- a/core/modules/filterrunprefixes/and.js +++ b/core/modules/filterrunprefixes/and.js @@ -19,9 +19,9 @@ Export our filter prefix function exports.and = function(operationSubFunction,options) { return function(results,source,widget) { // This replaces all the elements of the array, but keeps the actual array so that references to it are preserved - source = options.wiki.makeTiddlerIterator(results); - results.splice(0,results.length); - $tw.utils.pushTop(results,operationSubFunction(source,widget)); + source = options.wiki.makeTiddlerIterator(results.toArray()); + results.clear(); + results.pushTop(operationSubFunction(source,widget)); }; }; diff --git a/core/modules/filterrunprefixes/else.js b/core/modules/filterrunprefixes/else.js index c39b9e8fe..6e9ef29b3 100644 --- a/core/modules/filterrunprefixes/else.js +++ b/core/modules/filterrunprefixes/else.js @@ -19,7 +19,7 @@ exports.else = function(operationSubFunction) { return function(results,source,widget) { if(results.length === 0) { // Main result so far is empty - $tw.utils.pushTop(results,operationSubFunction(source,widget)); + results.pushTop(operationSubFunction(source,widget)); } }; }; diff --git a/core/modules/filterrunprefixes/except.js b/core/modules/filterrunprefixes/except.js index 18d649627..659f14228 100644 --- a/core/modules/filterrunprefixes/except.js +++ b/core/modules/filterrunprefixes/except.js @@ -18,7 +18,7 @@ Export our filter prefix function */ exports.except = function(operationSubFunction) { return function(results,source,widget) { - $tw.utils.removeArrayEntries(results,operationSubFunction(source,widget)); + results.remove(operationSubFunction(source,widget)); }; }; diff --git a/core/modules/filterrunprefixes/filter.js b/core/modules/filterrunprefixes/filter.js index 72b7ce24c..555f8981b 100644 --- a/core/modules/filterrunprefixes/filter.js +++ b/core/modules/filterrunprefixes/filter.js @@ -17,13 +17,13 @@ exports.filter = function(operationSubFunction,options) { return function(results,source,widget) { if(results.length > 0) { var resultsToRemove = []; - $tw.utils.each(results,function(result) { + results.each(function(result) { var filtered = operationSubFunction(options.wiki.makeTiddlerIterator([result]),widget); if(filtered.length === 0) { resultsToRemove.push(result); } }); - $tw.utils.removeArrayEntries(results,resultsToRemove); + results.remove(resultsToRemove); } } }; diff --git a/core/modules/filterrunprefixes/intersection.js b/core/modules/filterrunprefixes/intersection.js index 2874125d4..34d36066f 100644 --- a/core/modules/filterrunprefixes/intersection.js +++ b/core/modules/filterrunprefixes/intersection.js @@ -17,7 +17,8 @@ exports.intersection = function(operationSubFunction) { return function(results,source,widget) { if(results.length !== 0) { var secondRunResults = operationSubFunction(source,widget); - var firstRunResults = results.splice(0); + var firstRunResults = results.toArray(); + results.clear(); $tw.utils.each(firstRunResults,function(title) { if(secondRunResults.indexOf(title) !== -1) { results.push(title); @@ -27,4 +28,4 @@ exports.intersection = function(operationSubFunction) { }; }; -})(); \ No newline at end of file +})(); diff --git a/core/modules/filterrunprefixes/or.js b/core/modules/filterrunprefixes/or.js index 5192f490b..82eff083a 100644 --- a/core/modules/filterrunprefixes/or.js +++ b/core/modules/filterrunprefixes/or.js @@ -17,7 +17,7 @@ Export our filter prefix function */ exports.or = function(operationSubFunction) { return function(results,source,widget) { - $tw.utils.pushTop(results,operationSubFunction(source,widget)); + results.pushTop(operationSubFunction(source,widget)); }; }; diff --git a/core/modules/filterrunprefixes/reduce.js b/core/modules/filterrunprefixes/reduce.js index 4dcef4bc7..534c3e450 100644 --- a/core/modules/filterrunprefixes/reduce.js +++ b/core/modules/filterrunprefixes/reduce.js @@ -16,9 +16,9 @@ exports.reduce = function(operationSubFunction,options) { return function(results,source,widget) { if(results.length > 0) { var accumulator = ""; - for(var index=0; index 0) { accumulator = "" + list[0]; } - } - results.splice(0,results.length); + ++index; + }); + results.clear(); results.push(accumulator); } } diff --git a/core/modules/filters.js b/core/modules/filters.js index 0fc0a3dc9..4fec05964 100644 --- a/core/modules/filters.js +++ b/core/modules/filters.js @@ -311,11 +311,11 @@ exports.compileFilter = function(filterString) { } else if(typeof source === "object") { // Array or hashmap source = self.makeTiddlerIterator(source); } - var results = []; + var results = new $tw.utils.LinkedList(); $tw.utils.each(operationFunctions,function(operationFunction) { operationFunction(results,source,widget); }); - return results; + return results.toArray(); }); }; diff --git a/core/modules/utils/linked-list.js b/core/modules/utils/linked-list.js new file mode 100644 index 000000000..50421ab56 --- /dev/null +++ b/core/modules/utils/linked-list.js @@ -0,0 +1,118 @@ +/*\ +module-type: utils +title: $:/core/modules/utils/linkedlist.js +type: application/javascript + +This is a doubly-linked indexed list intended for manipulation, particularly +pushTop, which it does with significantly better performance than an array. + +\*/ +(function(){ + +function LinkedList() { + this.clear(); +}; + +LinkedList.prototype.clear = function() { + this.index = Object.create(null); + // LinkedList performs the duty of both the head and tail node + this.next = this; + this.prev = this; + this.length = 0; +}; + +LinkedList.prototype.remove = function(value) { + if($tw.utils.isArray(value)) { + for(var t=0; t