You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

199 lines
4.5 KiB

'use strict'
var xtend = require('xtend')
var reusify = require('reusify')
var defaults = {
released: nop,
results: true
}
function fastparallel (options) {
options = xtend(defaults, options)
var released = options.released
var queue = reusify(options.results ? ResultsHolder : NoResultsHolder)
var queueSingleCaller = reusify(SingleCaller)
var goArray = options.results ? goResultsArray : goNoResultsArray
var goFunc = options.results ? goResultsFunc : goNoResultsFunc
return parallel
function parallel (that, toCall, arg, done) {
var holder = queue.get()
done = done || nop
if (toCall.length === 0) {
done.call(that)
released(holder)
} else {
holder._callback = done
holder._callThat = that
holder._release = release
if (typeof toCall === 'function') {
goFunc(that, toCall, arg, holder)
} else {
goArray(that, toCall, arg, holder)
}
if (holder._count === 0) {
holder.release()
}
}
}
function release (holder) {
queue.release(holder)
released(holder)
}
function singleCallerRelease (holder) {
queueSingleCaller.release(holder)
}
function goResultsFunc (that, toCall, arg, holder) {
var singleCaller = null
holder._count = arg.length
holder._results = new Array(holder._count)
for (var i = 0; i < arg.length; i++) {
singleCaller = queueSingleCaller.get()
singleCaller._release = singleCallerRelease
singleCaller.parent = holder
singleCaller.pos = i
if (that) {
toCall.call(that, arg[i], singleCaller.release)
} else {
toCall(arg[i], singleCaller.release)
}
}
}
function goResultsArray (that, funcs, arg, holder) {
var sc = null
var tc = nop
holder._count = funcs.length
holder._results = new Array(holder._count)
for (var i = 0; i < funcs.length; i++) {
sc = queueSingleCaller.get()
sc._release = singleCallerRelease
sc.parent = holder
sc.pos = i
tc = funcs[i]
if (that) {
if (tc.length === 1) tc.call(that, sc.release)
else tc.call(that, arg, sc.release)
} else {
if (tc.length === 1) tc(sc.release)
else tc(arg, sc.release)
}
}
}
function goNoResultsFunc (that, toCall, arg, holder) {
holder._count = arg.length
for (var i = 0; i < arg.length; i++) {
if (that) {
toCall.call(that, arg[i], holder.release)
} else {
toCall(arg[i], holder.release)
}
}
}
function goNoResultsArray (that, funcs, arg, holder) {
var toCall = null
holder._count = funcs.length
for (var i = 0; i < funcs.length; i++) {
toCall = funcs[i]
if (that) {
if (toCall.length === 1) {
toCall.call(that, holder.release)
} else {
toCall.call(that, arg, holder.release)
}
} else {
if (toCall.length === 1) {
toCall(holder.release)
} else {
toCall(arg, holder.release)
}
}
}
}
}
function NoResultsHolder () {
this._count = -1
this._callback = nop
this._callThat = null
this._release = null
this.next = null
var that = this
var i = 0
this.release = function () {
var cb = that._callback
if (++i === that._count || that._count === 0) {
if (that._callThat) {
cb.call(that._callThat)
} else {
cb()
}
that._callback = nop
that._callThat = null
that._release(that)
i = 0
}
}
}
function SingleCaller () {
this.pos = -1
this._release = nop
this.parent = null
this.next = null
var that = this
this.release = function (err, result) {
that.parent.release(err, that.pos, result)
that.pos = -1
that.parent = null
that._release(that)
}
}
function ResultsHolder () {
this._count = -1
this._callback = nop
this._results = null
this._err = null
this._callThat = null
this._release = nop
this.next = null
var that = this
var i = 0
this.release = function (err, pos, result) {
that._err = that._err || err
if (pos >= 0) {
that._results[pos] = result
}
var cb = that._callback
if (++i === that._count || that._count === 0) {
if (that._callThat) {
cb.call(that._callThat, that._err, that._results)
} else {
cb(that._err, that._results)
}
that._callback = nop
that._results = null
that._err = null
that._callThat = null
i = 0
that._release(that)
}
}
}
function nop () { }
module.exports = fastparallel