Ver código fonte

Added linked list to mol-data, refactoring

David Sehnal 7 anos atrás
pai
commit
f16c699d3b

+ 9 - 0
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'

+ 63 - 0
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([]);
+    })
+});

+ 0 - 0
src/mol-data/util/hash-set.ts → src/mol-data/generic/hash-set.ts


+ 119 - 0
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 }

+ 0 - 0
src/mol-data/util/unique-array.ts → src/mol-data/generic/unique-array.ts


+ 2 - 1
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 }
+export { DB, Int, Iterator, Util, Generic }

+ 0 - 2
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'

+ 1 - 1
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();

+ 1 - 1
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

+ 1 - 1
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'

+ 1 - 1
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>

+ 52 - 3
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) {

+ 2 - 1
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 }
+export { Task, RuntimeContext, Progress, Run, now }

+ 6 - 7
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

+ 0 - 0
src/mol-task/util/chunked.ts


+ 0 - 0
src/mol-task/util/multistep.ts


+ 0 - 0
src/mol-task/time.ts → src/mol-task/util/now.ts