From 3dc9f8f1e120f0c95f67221ac0d1a9bac7b88cd4 Mon Sep 17 00:00:00 2001 From: Alexander Early Date: Thu, 6 Apr 2017 22:17:49 -0700 Subject: [PATCH 1/3] added tests for DLL, filter(), non-leaking empty() --- lib/internal/DoublyLinkedList.js | 28 ++++++++++- mocha_test/linked_list.js | 83 ++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 mocha_test/linked_list.js diff --git a/lib/internal/DoublyLinkedList.js b/lib/internal/DoublyLinkedList.js index 79c3bb50e..0feea1b1a 100644 --- a/lib/internal/DoublyLinkedList.js +++ b/lib/internal/DoublyLinkedList.js @@ -23,7 +23,10 @@ DLL.prototype.removeLink = function(node) { return node; } -DLL.prototype.empty = DLL; +DLL.prototype.empty = function () { + while(this.head) this.shift(); + return this; +}; DLL.prototype.insertAfter = function(node, newNode) { newNode.prev = node; @@ -60,3 +63,26 @@ DLL.prototype.shift = function() { DLL.prototype.pop = function() { return this.tail && this.removeLink(this.tail); }; + +DLL.prototype.toArray = function () { + var arr = Array(this.length); + var idx = 0; + var curr = this.head; + for(idx = 0; idx < this.length; idx++) { + arr[idx] = curr.data; + curr = curr.next; + } + return arr; +} + +DLL.prototype.filter = function (testFn) { + var curr = this.head; + while(!!curr) { + var next = curr.next; + if (!testFn(curr)) { + this.removeLink(curr); + } + curr = next; + } + return this; +} diff --git a/mocha_test/linked_list.js b/mocha_test/linked_list.js new file mode 100644 index 000000000..19cb1550d --- /dev/null +++ b/mocha_test/linked_list.js @@ -0,0 +1,83 @@ +var DLL = require('../lib/internal/DoublyLinkedList').default; +var expect = require('chai').expect; + +describe('DoublyLinkedList', function () { + it('toArray', function() { + var list = new DLL(); + expect(list.toArray()).to.eql([]); + + for (var i = 0; i < 5; i++) { + list.push({data: i}); + } + expect(list.toArray()).to.eql([0, 1, 2, 3, 4]); + }); + + it('filter', function() { + var list = new DLL(); + + for (var i = 0; i < 5; i++) { + list.push({data: i}); + } + + list.filter(function (node) { + return node.data !== 3; + }) + + expect(list.toArray()).to.eql([0, 1, 2, 4]); + }); + + it('filter (head)', function() { + var list = new DLL(); + + for (var i = 0; i < 5; i++) { + list.push({data: i}); + } + + list.filter(function (node) { + return node.data !== 0; + }) + + expect(list.toArray()).to.eql([1, 2, 3, 4]); + }); + + it('filter (tail)', function() { + var list = new DLL(); + + for (var i = 0; i < 5; i++) { + list.push({data: i}); + } + + list.filter(function (node) { + return node.data !== 4; + }) + + expect(list.toArray()).to.eql([0, 1, 2, 3]); + }); + + it('filter (all)', function() { + var list = new DLL(); + + for (var i = 0; i < 5; i++) { + list.push({data: i}); + } + + list.filter(function (node) { + return node.data > 5; + }) + + expect(list.toArray()).to.eql([]); + }); + + it('empty', function() { + var list = new DLL(); + + for (var i = 0; i < 5; i++) { + list.push({data: i}); + } + + var empty = list.empty(); + + expect(list).to.equal(empty); + expect(list.toArray()).to.eql([]); + }); +}); From 291c81138258cd22be3a9bc9b2f1990eacaba634 Mon Sep 17 00:00:00 2001 From: Alexander Early Date: Thu, 6 Apr 2017 22:34:11 -0700 Subject: [PATCH 2/3] add queue.remove --- lib/internal/queue.js | 5 +++++ lib/queue.js | 6 ++++++ mocha_test/queue.js | 19 +++++++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/lib/internal/queue.js b/lib/internal/queue.js index 479eaf87b..87d49f498 100644 --- a/lib/internal/queue.js +++ b/lib/internal/queue.js @@ -102,6 +102,11 @@ export default function queue(worker, concurrency, payload) { unshift: function (data, callback) { _insert(data, true, callback); }, + remove: function (testFn) { + q._tasks = q._tasks.filter(function (node) { + return !testFn(node); + }) + }, process: function () { // Avoid trying to start too many processing operations. This can occur // when callbacks resolve synchronously (#1267). diff --git a/lib/queue.js b/lib/queue.js index 906467c07..2d0abb7a9 100644 --- a/lib/queue.js +++ b/lib/queue.js @@ -24,6 +24,12 @@ import wrapAsync from './internal/wrapAsync'; * task in the list. Invoke with `queue.push(task, [callback])`, * @property {Function} unshift - add a new task to the front of the `queue`. * Invoke with `queue.unshift(task, [callback])`. + * @property {Function} remove - remove items from the queue that match a test + * function. The test function will be passed an object with a `data` property, + * and a `priority` property, if this is a + * [priorityQueue]{@link module:ControlFlow.priorityQueue} object. + * Invoked with `queue.remove(testFn)`, where `testFn` is of the form + * `function ({data, priority}) {}` and returns a Boolean. * @property {Function} saturated - a callback that is called when the number of * running workers hits the `concurrency` limit, and further tasks will be * queued. diff --git a/mocha_test/queue.js b/mocha_test/queue.js index cc72c52c5..77d4710e1 100644 --- a/mocha_test/queue.js +++ b/mocha_test/queue.js @@ -761,5 +761,24 @@ describe('queue', function(){ q.push('foo4', function () {calls.push('foo4 cb');}); }); }); + + it('remove', function(done) { + var result = []; + var q = async.queue(function(data, cb) { + result.push(data); + async.setImmediate(cb); + }); + + q.push([1, 2, 3, 4, 5]); + + q.remove(function (node) { + return node.data === 3; + }); + + q.drain = function () { + expect(result).to.eql([1, 2, 4, 5]); + done(); + } + }); }); From 07402822c3125a019c3060104eb7da54e0ccc5b6 Mon Sep 17 00:00:00 2001 From: Alexander Early Date: Sat, 8 Apr 2017 18:24:59 -0700 Subject: [PATCH 3/3] rename filter to remove --- lib/internal/DoublyLinkedList.js | 4 ++-- lib/internal/queue.js | 4 +--- mocha_test/linked_list.js | 24 ++++++++++++------------ 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/lib/internal/DoublyLinkedList.js b/lib/internal/DoublyLinkedList.js index 0feea1b1a..0e3b39435 100644 --- a/lib/internal/DoublyLinkedList.js +++ b/lib/internal/DoublyLinkedList.js @@ -75,11 +75,11 @@ DLL.prototype.toArray = function () { return arr; } -DLL.prototype.filter = function (testFn) { +DLL.prototype.remove = function (testFn) { var curr = this.head; while(!!curr) { var next = curr.next; - if (!testFn(curr)) { + if (testFn(curr)) { this.removeLink(curr); } curr = next; diff --git a/lib/internal/queue.js b/lib/internal/queue.js index 87d49f498..f05856881 100644 --- a/lib/internal/queue.js +++ b/lib/internal/queue.js @@ -103,9 +103,7 @@ export default function queue(worker, concurrency, payload) { _insert(data, true, callback); }, remove: function (testFn) { - q._tasks = q._tasks.filter(function (node) { - return !testFn(node); - }) + q._tasks.remove(testFn); }, process: function () { // Avoid trying to start too many processing operations. This can occur diff --git a/mocha_test/linked_list.js b/mocha_test/linked_list.js index 19cb1550d..ab4b22335 100644 --- a/mocha_test/linked_list.js +++ b/mocha_test/linked_list.js @@ -12,57 +12,57 @@ describe('DoublyLinkedList', function () { expect(list.toArray()).to.eql([0, 1, 2, 3, 4]); }); - it('filter', function() { + it('remove', function() { var list = new DLL(); for (var i = 0; i < 5; i++) { list.push({data: i}); } - list.filter(function (node) { - return node.data !== 3; + list.remove(function (node) { + return node.data === 3; }) expect(list.toArray()).to.eql([0, 1, 2, 4]); }); - it('filter (head)', function() { + it('remove (head)', function() { var list = new DLL(); for (var i = 0; i < 5; i++) { list.push({data: i}); } - list.filter(function (node) { - return node.data !== 0; + list.remove(function (node) { + return node.data === 0; }) expect(list.toArray()).to.eql([1, 2, 3, 4]); }); - it('filter (tail)', function() { + it('remove (tail)', function() { var list = new DLL(); for (var i = 0; i < 5; i++) { list.push({data: i}); } - list.filter(function (node) { - return node.data !== 4; + list.remove(function (node) { + return node.data === 4; }) expect(list.toArray()).to.eql([0, 1, 2, 3]); }); - it('filter (all)', function() { + it('remove (all)', function() { var list = new DLL(); for (var i = 0; i < 5; i++) { list.push({data: i}); } - list.filter(function (node) { - return node.data > 5; + list.remove(function (node) { + return node.data < 5; }) expect(list.toArray()).to.eql([]);