From cd246b25d6881f8f3ba954f78944dd34e890df33 Mon Sep 17 00:00:00 2001
From: David Sehnal <david.sehnal@gmail.com>
Date: Sat, 28 Oct 2017 20:35:44 +0200
Subject: [PATCH] column

---
 src/mol-base/collections/column.ts | 33 +++++++++++++
 src/perf-tests/column.ts           | 78 ++++++++++++++++++++++++++++++
 2 files changed, 111 insertions(+)
 create mode 100644 src/perf-tests/column.ts

diff --git a/src/mol-base/collections/column.ts b/src/mol-base/collections/column.ts
index 6139a04f4..b9ec618e0 100644
--- a/src/mol-base/collections/column.ts
+++ b/src/mol-base/collections/column.ts
@@ -35,6 +35,13 @@ namespace Column {
         end?: number
     }
 
+    export interface LambdaSpec<T extends Type> {
+        value: (row: number) => T['@type'],
+        rowCount: number,
+        type: T,
+        valueKind?: (row: number) => ValueKind,
+    }
+
     export interface ArraySpec<T extends Type> {
         array: ArrayLike<T['@type']>,
         type: T,
@@ -51,6 +58,10 @@ namespace Column {
         return constColumn(v, rowCount, type, ValueKind.Present);
     }
 
+    export function ofLambda<T extends Type>(spec: LambdaSpec<T>): Column<T['@type']> {
+        return lambdaColumn(spec);
+    }
+
     export function ofArray<T extends Column.Type>(spec: Column.ArraySpec<T>): Column<T['@type']> {
         return arrayColumn(spec);
     }
@@ -92,6 +103,28 @@ function constColumn<T extends Column.Type>(v: T['@type'], rowCount: number, typ
     }
 }
 
+function lambdaColumn<T extends Column.Type>({ value, valueKind, rowCount, type }: Column.LambdaSpec<T>): Column<T['@type']> {
+    return {
+        '@type': type,
+        '@array': void 0,
+        isDefined: true,
+        rowCount,
+        value,
+        valueKind: valueKind ? valueKind : row => Column.ValueKind.Present,
+        toArray: params => {
+            const { array, start } = createArray(rowCount, params);
+            for (let i = 0, _i = array.length; i < _i; i++) array[i] = value(i + start);
+            return array;
+        },
+        stringEquals: type.kind === 'str'
+            ? (row, v) => value(row) === v
+            : type.kind === 'float' || type.kind === 'int'
+            ? (row, v) => value(row) === +v
+            : (row, value) => false,
+        areValuesEqual: (rowA, rowB) => value(rowA) === value(rowB)
+    }
+}
+
 function arrayColumn<T extends Column.Type>({ array, type, valueKind }: Column.ArraySpec<T>): Column<T['@type']> {
     const rowCount = array.length;
     const value: Column<T['@type']>['value'] = type.kind === 'str'
diff --git a/src/perf-tests/column.ts b/src/perf-tests/column.ts
new file mode 100644
index 000000000..c5173a57b
--- /dev/null
+++ b/src/perf-tests/column.ts
@@ -0,0 +1,78 @@
+import * as B from 'benchmark'
+import C from '../mol-base/collections/column'
+
+export namespace Column {
+    function createData(n: number) {
+        const ret = new Float32Array(n);
+        for (let i = 0; i < n; i++) {
+            ret[i] = i * i + 1;
+        }
+        return ret;
+    }
+
+    function raw(xs: ArrayLike<number>) {
+        let sum = 0;
+        for (let i = 0, _i = xs.length; i < _i; i++) {
+            sum += xs[i];
+        }
+        return sum;
+    }
+
+    function column(col: C<number>) {
+        let sum = 0;
+        for (let i = 0, _i = col.rowCount; i < _i; i++) {
+            sum += col.value(i);
+        }
+        return sum;
+    }
+
+    function column1(col: C<number>) {
+        let sum = 0;
+        for (let i = 0, _i = col.rowCount; i < _i; i++) {
+            sum += col.value(i);
+        }
+        return sum;
+    }
+
+    function val(i: number) { return i * i + 1; }
+
+    export function runMono() {
+        const suite = new B.Suite();
+        const data = createData(1000);
+        const nativeData = [...data as any];
+        const col = C.ofArray({ array: data, type: C.Type.float });
+        const lambda = C.ofLambda({ value: val, rowCount: data.length, type: C.Type.float });
+        const cnst = C.ofConst(10, data.length, C.Type.float);
+        suite
+            .add('raw', () => raw(data))
+            .add('native raw', () => raw(nativeData))
+            .add('arraycol', () => column(col))
+            .add('arraycol1', () => column(col))
+            .add('const', () => column1(cnst))
+            .add('arraycol2', () => column(col))
+            .add('lambda', () => column1(lambda))
+            .on('cycle', (e: any) => console.log(String(e.target)))
+            .run();
+    }
+
+    export function runPoly() {
+        const suite = new B.Suite();
+        const data = createData(10000);
+        const nativeData = [...data as any];
+        const col = C.ofArray({ array: data, type: C.Type.float });
+        const lambda = C.ofLambda({ value: val, rowCount: data.length, type: C.Type.float });
+        const cnst = C.ofConst(10, data.length, C.Type.float);
+        suite
+            .add('raw', () => raw(data))
+            .add('native raw', () => raw(nativeData))
+            .add('arraycol', () => column(col))
+            .add('const', () => column(cnst))
+            .add('arraycol2', () => column(col))
+            .add('lambda', () => column(lambda))
+            .on('cycle', (e: any) => console.log(String(e.target)))
+            .run();
+    }
+}
+
+Column.runMono();
+Column.runPoly();
\ No newline at end of file
-- 
GitLab