diff --git a/src/mol-data/generic.ts b/src/mol-data/generic.ts new file mode 100644 index 0000000000000000000000000000000000000000..d837d1060ef77cafd9a0cf7c493a05f90b2a03b2 --- /dev/null +++ b/src/mol-data/generic.ts @@ -0,0 +1,9 @@ +/** + * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + */ + +export * from './generic/hash-set' +export * from './generic/linked-list' +export * from './generic/unique-array' \ No newline at end of file diff --git a/src/mol-data/generic/_spec/linked-list.spec.ts b/src/mol-data/generic/_spec/linked-list.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..cb439b3da78117e85734fa39ffd040f86cc260a5 --- /dev/null +++ b/src/mol-data/generic/_spec/linked-list.spec.ts @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + */ + +import { LinkedList } from '../linked-list' + +describe('linked list', () => { + + function toArray<T>(list: LinkedList<T>) { + const ret: T[] = []; + for (let t = list.first; !!t; t = t.next) { + ret[ret.length] = t.value; + } + return ret; + } + + function create<T>(xs: T[]) { + const list = LinkedList<T>(); + for (const x of xs) list.addLast(x); + return list; + } + + it('add', () => { + const list = LinkedList<number>(); + list.addFirst(1); + list.addLast(2); + list.addFirst(3); + list.addFirst(4); + list.addLast(5); + expect(toArray(list)).toEqual([4, 3, 1, 2, 5]); + expect(list.count).toBe(5); + }); + + it ('remove', () => { + const list = create([1, 2, 3, 4]); + let fst = list.removeFirst(); + expect(fst).toBe(1); + expect(list.last!.value).toBe(4); + expect(list.count).toBe(3); + expect(toArray(list)).toEqual([2, 3, 4]); + + let last = list.removeLast(); + expect(last).toBe(4); + expect(list.last!.value).toBe(3); + expect(list.count).toBe(2); + expect(toArray(list)).toEqual([2, 3]); + + let n3 = list.find(3)!; + list.remove(n3); + expect(list.first!.value).toBe(2); + expect(list.last!.value).toBe(2); + expect(list.count).toBe(1); + expect(toArray(list)).toEqual([2]); + + list.removeFirst(); + expect(list.first).toBe(null); + expect(list.last).toBe(null); + expect(list.count).toBe(0); + expect(toArray(list)).toEqual([]); + }) +}); \ No newline at end of file diff --git a/src/mol-data/util/hash-set.ts b/src/mol-data/generic/hash-set.ts similarity index 100% rename from src/mol-data/util/hash-set.ts rename to src/mol-data/generic/hash-set.ts diff --git a/src/mol-data/generic/linked-list.ts b/src/mol-data/generic/linked-list.ts new file mode 100644 index 0000000000000000000000000000000000000000..3f54226999dec6cb4b33ac447e0342ace9a05abf --- /dev/null +++ b/src/mol-data/generic/linked-list.ts @@ -0,0 +1,119 @@ +/** + * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + */ + +interface LinkedList<T> { + readonly count: number, + readonly first: LinkedList.Node<T> | null, + readonly last: LinkedList.Node<T> | null, + addFirst(value: T): LinkedList.Node<T>, + addLast(value: T): LinkedList.Node<T>, + remove(node: LinkedList.Node<T>): void, + removeFirst(): T | undefined, + removeLast(): T | undefined, + find(value: T): LinkedList.Node<T> | undefined +} + +function LinkedList<T>(): LinkedList<T> { + return new LinkedListImpl(); +} + +namespace LinkedList { + export interface Node<T> { + previous: Node<T> | null, + next: Node<T> | null, + inList: boolean, + value: T + } +} + +function createListNode<T>(value: T): LinkedList.Node<T> { + return { previous: null, next: null, inList: true, value }; +} + +class LinkedListImpl<T> implements LinkedList<T> { + count: number = 0; + first: LinkedList.Node<T> | null = null; + last: LinkedList.Node<T> | null = null; + + addFirst(value: T) { + const node = createListNode(value); + node.inList = true; + if (this.first) this.first.previous = node; + node.next = this.first; + this.first = node; + this.count++; + if (!this.last) this.last = node; + return node; + } + + addLast(value: T) { + const node = createListNode(value); + if (this.last !== null) { + this.last.next = node; + } + node.previous = this.last; + this.last = node; + if (this.first === null) { + this.first = node; + } + node.inList = true; + this.count++; + return node; + } + + removeFirst(): T | undefined { + const fst = this.first; + if (fst) { + this.remove(fst); + return fst.value; + } + return void 0; + } + + removeLast(): T | undefined { + const last = this.last; + if (last) { + this.remove(last); + return last.value; + } + return void 0; + } + + remove(node: LinkedList.Node<T>) { + if (!node.inList) return; + + node.inList = false; + + if (node.previous !== null) { + node.previous.next = node.next; + } + else if (/*first == item*/ node.previous === null) { + this.first = node.next; + } + + if (node.next !== null) { + node.next.previous = node.previous; + } + else if (/*last == item*/ node.next === null) { + this.last = node.previous; + } + + node.next = null; + node.previous = null; + this.count--; + } + + find(value: T): LinkedList.Node<T> | undefined { + let current = this.first; + while (current !== null) { + if (current.value === value) return current; + current = current.next; + } + return void 0; + } +} + +export { LinkedList } \ No newline at end of file diff --git a/src/mol-data/util/unique-array.ts b/src/mol-data/generic/unique-array.ts similarity index 100% rename from src/mol-data/util/unique-array.ts rename to src/mol-data/generic/unique-array.ts diff --git a/src/mol-data/index.ts b/src/mol-data/index.ts index 1db90c26e324d3098c0a50b16b3ec2f957f37f4e..b1d2500848e1069a962d90d252e76406d47a9441 100644 --- a/src/mol-data/index.ts +++ b/src/mol-data/index.ts @@ -8,5 +8,6 @@ import * as DB from './db' import * as Int from './int' import Iterator from './iterator' import * as Util from './util' +import * as Generic from './generic' -export { DB, Int, Iterator, Util } \ No newline at end of file +export { DB, Int, Iterator, Util, Generic } \ No newline at end of file diff --git a/src/mol-data/util.ts b/src/mol-data/util.ts index 629b3b517d6f1ad80151a734f369083529c00ba5..c541a1e9e9dc71678081bc32c4f158fda3b18b39 100644 --- a/src/mol-data/util.ts +++ b/src/mol-data/util.ts @@ -5,8 +5,6 @@ */ export * from './util/chunked-array' -export * from './util/unique-array' -export * from './util/hash-set' export * from './util/equivalence-classes' export * from './util/hash-functions' export * from './util/sort' diff --git a/src/mol-data/util/array.ts b/src/mol-data/util/array.ts index 664138327b5b67fab885efd6e0ec035f6efaf895..93707e7978d657144d2b487a4c665c5f8eaf0198 100644 --- a/src/mol-data/util/array.ts +++ b/src/mol-data/util/array.ts @@ -14,7 +14,7 @@ export function arrayFind<T>(array: ArrayLike<T>, f: (v: T) => boolean): T | und export function iterableToArray<T>(it: IterableIterator<T>): T[] { if (Array.from) return Array.from(it); - + const ret = []; while (true) { const { done, value } = it.next(); diff --git a/src/mol-model/structure/query/selection.ts b/src/mol-model/structure/query/selection.ts index 2d8467e0764f13993077c5d6a49761ec66874acc..5b317240a2e1d02530c36f4c0ecf3e130965a96c 100644 --- a/src/mol-model/structure/query/selection.ts +++ b/src/mol-model/structure/query/selection.ts @@ -4,7 +4,7 @@ * @author David Sehnal <david.sehnal@gmail.com> */ -import { HashSet } from 'mol-data/util' +import { HashSet } from 'mol-data/generic' import { Structure, AtomSet } from '../structure' // A selection is a pair of a Structure and a sequence of unique AtomSets diff --git a/src/mol-model/structure/structure/structure.ts b/src/mol-model/structure/structure/structure.ts index 6cac5a7b8c4e05f9fdfc96abb12e902f68ae7bda..dfd764e4750977b8fb576f252ebbd4f838a5ef74 100644 --- a/src/mol-model/structure/structure/structure.ts +++ b/src/mol-model/structure/structure/structure.ts @@ -5,7 +5,7 @@ */ import { OrderedSet, Iterator } from 'mol-data/int' -import { UniqueArray } from 'mol-data/util' +import { UniqueArray } from 'mol-data/generic' import SymmetryOperator from 'mol-math/geometry/symmetry-operator' import { Model, Format } from '../model' import Unit from './unit' diff --git a/src/mol-task/computation.ts b/src/mol-task/computation.ts index 3d956de70054e16b858a96c080393ac582517ab7..b4b1c9d1398f1afb41fc28585f6269f6011e5a7c 100644 --- a/src/mol-task/computation.ts +++ b/src/mol-task/computation.ts @@ -6,7 +6,7 @@ */ import Scheduler from './scheduler' -import timeNow from './time' +import timeNow from './util/now' interface Computation<A> { (ctx?: Computation.Context): Promise<A> diff --git a/src/mol-task/execution/observable.ts b/src/mol-task/execution/observable.ts index f06abbf0c63a3f6bbb33b977c118256472f68512..44fa6517005f7f643a477a90adde8e2155a6d05b 100644 --- a/src/mol-task/execution/observable.ts +++ b/src/mol-task/execution/observable.ts @@ -7,10 +7,38 @@ import Task from '../task' import RuntimeContext from './runtime-context' import Progress from './progress' +import now from '../util/now' + +function defaultProgress(rootTaskId: number, task: Task<any>): Task.Progress { + return { + rootTaskId, + taskId: task.id, + taskName: task.name, + message: 'Running...', + elapsedMs: { real: 0, cpu: 0 }, + canAbort: true, + isIndeterminate: true, + current: 0, + max: 0 + }; +} + +class ProgressInfo { + taskId: number; + elapsedMs: { real: number, cpu: number }; + tree: Progress.Node; + tryAbort?: (reason?: string) => void; + + snapshot(): Progress { + return 0 as any; + } +} class ObservableExecutor { + progressInfo: ProgressInfo; + async run<T>(task: Task<T>): Promise<T> { - const ctx = new ObservableRuntimeContext(); + const ctx = new ObservableRuntimeContext(task.id, task, 0); if (!task.__onAbort) return task.__f(ctx); try { @@ -27,14 +55,35 @@ class ObservableExecutor { } class ObservableRuntimeContext implements RuntimeContext { - id: number = 0; - requiresUpdate: boolean = false; + elapsedCpuMs: number; + lastScheduledTime: number; + + started: number; + taskId: number; + taskName: string; + progress: Task.Progress; + updateRateMs: number; + + get requiresUpdate(): boolean { + return now() - this.started > this.updateRateMs; + } + update(progress: Partial<RuntimeContext.ProgressUpdate>): Promise<void> { return 0 as any; } + runChild<T>(progress: Partial<RuntimeContext.ProgressUpdate>, task: Task<T>): Promise<T> { return 0 as any; } + + constructor(parentId: number, task: Task<any>, updateRateMs: number) { + this.started = now(); + this.lastScheduledTime = this.started; + this.taskId = task.id; + this.taskName = task.name; + this.progress = defaultProgress(parentId, task); + this.updateRateMs = updateRateMs; + } } function ExecuteObservable<T>(task: Task<T>, observer: Progress.Observer, updateRateMs = 250) { diff --git a/src/mol-task/index.ts b/src/mol-task/index.ts index d9626148cff8d0fd8f9053ee36fa54580aadaa76..6367cb572230811dca426af48d3f5be4884ebead 100644 --- a/src/mol-task/index.ts +++ b/src/mol-task/index.ts @@ -9,6 +9,7 @@ import RuntimeContext from './execution/runtime-context' import ExecuteSynchronous from './execution/synchronous' import ExecuteObservable from './execution/observable' import Progress from './execution/progress' +import now from './util/now' function Run<T>(task: Task<T>): Promise<T>; function Run<T>(task: Task<T>, observer: Progress.Observer, updateRateMs?: number): Promise<T>; @@ -17,4 +18,4 @@ function Run<T>(task: Task<T>, observer?: Progress.Observer, updateRateMs?: numb return ExecuteSynchronous(task); } -export { Task, RuntimeContext, Progress, Run } \ No newline at end of file +export { Task, RuntimeContext, Progress, Run, now } \ No newline at end of file diff --git a/src/mol-task/task.ts b/src/mol-task/task.ts index e0e5174a99ce79b11cb12ee30cc7194f4bdfc40e..8f6a700c321e2a18b812e74e694a0d1fccb99e50 100644 --- a/src/mol-task/task.ts +++ b/src/mol-task/task.ts @@ -35,18 +35,17 @@ namespace Task { return ret; } - export type Progress = IndeterminateProgress | DeterminateProgress - - interface ProgressBase { + export interface Progress { rootTaskId: number, taskId: number, + taskName: string, message: string, elapsedMs: { real: number, cpu: number }, - canAbort: boolean + canAbort: boolean, + isIndeterminate: boolean, + current: number, + max: number } - - export interface IndeterminateProgress extends ProgressBase { isIndeterminate: true } - export interface DeterminateProgress extends ProgressBase { isIndeterminate: false, current: number, max: number } } export default Task \ No newline at end of file diff --git a/src/mol-task/util/chunked.ts b/src/mol-task/util/chunked.ts new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/mol-task/util/multistep.ts b/src/mol-task/util/multistep.ts new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/mol-task/time.ts b/src/mol-task/util/now.ts similarity index 100% rename from src/mol-task/time.ts rename to src/mol-task/util/now.ts