pnpm
Version:
Fast, disk space efficient package manager
126 lines (99 loc) • 2.73 kB
JavaScript
/** @license MIT License (c) copyright 2010-2016 original author or authors */
/** @author Brian Cavalier */
/** @author John Hann */
import * as base from '@most/prelude'
export default function Timeline () {
this.tasks = []
}
Timeline.prototype.nextArrival = function () {
return this.isEmpty() ? Infinity : this.tasks[0].time
}
Timeline.prototype.isEmpty = function () {
return this.tasks.length === 0
}
Timeline.prototype.add = function (st) {
insertByTime(st, this.tasks)
}
Timeline.prototype.remove = function (st) {
var i = binarySearch(st.time, this.tasks)
if (i >= 0 && i < this.tasks.length) {
var at = base.findIndex(st, this.tasks[i].events)
if (at >= 0) {
this.tasks[i].events.splice(at, 1)
return true
}
}
return false
}
Timeline.prototype.removeAll = function (f) {
for (var i = 0, l = this.tasks.length; i < l; ++i) {
removeAllFrom(f, this.tasks[i])
}
}
Timeline.prototype.runTasks = function (t, runTask) {
var tasks = this.tasks
var l = tasks.length
var i = 0
while (i < l && tasks[i].time <= t) {
++i
}
this.tasks = tasks.slice(i)
// Run all ready tasks
for (var j = 0; j < i; ++j) {
this.tasks = runTasks(runTask, tasks[j], this.tasks)
}
}
function runTasks (runTask, timeslot, tasks) { // eslint-disable-line complexity
var events = timeslot.events
for (var i = 0; i < events.length; ++i) {
var task = events[i]
if (task.active) {
runTask(task)
// Reschedule periodic repeating tasks
// Check active again, since a task may have canceled itself
if (task.period >= 0 && task.active) {
task.time = task.time + task.period
insertByTime(task, tasks)
}
}
}
return tasks
}
function insertByTime (task, timeslots) { // eslint-disable-line complexity
var l = timeslots.length
if (l === 0) {
timeslots.push(newTimeslot(task.time, [task]))
return
}
var i = binarySearch(task.time, timeslots)
if (i >= l) {
timeslots.push(newTimeslot(task.time, [task]))
} else if (task.time === timeslots[i].time) {
timeslots[i].events.push(task)
} else {
timeslots.splice(i, 0, newTimeslot(task.time, [task]))
}
}
function removeAllFrom (f, timeslot) {
timeslot.events = base.removeAll(f, timeslot.events)
}
function binarySearch (t, sortedArray) { // eslint-disable-line complexity
var lo = 0
var hi = sortedArray.length
var mid, y
while (lo < hi) {
mid = Math.floor((lo + hi) / 2)
y = sortedArray[mid]
if (t === y.time) {
return mid
} else if (t < y.time) {
hi = mid
} else {
lo = mid + 1
}
}
return hi
}
function newTimeslot (t, events) {
return { time: t, events: events }
}