diff --git a/lib/internal/DoublyLinkedList.js b/lib/internal/DoublyLinkedList.js index 79c3bb50e..0e3b39435 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.remove = 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/lib/internal/queue.js b/lib/internal/queue.js index 479eaf87b..f05856881 100644 --- a/lib/internal/queue.js +++ b/lib/internal/queue.js @@ -102,6 +102,9 @@ export default function queue(worker, concurrency, payload) { unshift: function (data, callback) { _insert(data, true, callback); }, + remove: function (testFn) { + q._tasks.remove(testFn); + }, 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/linked_list.js b/mocha_test/linked_list.js new file mode 100644 index 000000000..ab4b22335 --- /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('remove', function() { + var list = new DLL(); + + for (var i = 0; i < 5; i++) { + list.push({data: i}); + } + + list.remove(function (node) { + return node.data === 3; + }) + + expect(list.toArray()).to.eql([0, 1, 2, 4]); + }); + + it('remove (head)', function() { + var list = new DLL(); + + for (var i = 0; i < 5; i++) { + list.push({data: i}); + } + + list.remove(function (node) { + return node.data === 0; + }) + + expect(list.toArray()).to.eql([1, 2, 3, 4]); + }); + + it('remove (tail)', function() { + var list = new DLL(); + + for (var i = 0; i < 5; i++) { + list.push({data: i}); + } + + list.remove(function (node) { + return node.data === 4; + }) + + expect(list.toArray()).to.eql([0, 1, 2, 3]); + }); + + it('remove (all)', function() { + var list = new DLL(); + + for (var i = 0; i < 5; i++) { + list.push({data: i}); + } + + list.remove(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([]); + }); +}); 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(); + } + }); });