Browse Source

ArrayColumn

David Sehnal 7 years ago
parent
commit
b4b329bea5

+ 5 - 1
src/mol-data/atom-set/builder.ts

@@ -24,7 +24,11 @@ class Builder {
 
     beginUnit() { this.currentUnit = []; }
     addToUnit(a: number) { this.currentUnit[this.currentUnit.length] = a; }
-    commitUnit(u: number) { if (this.currentUnit.length === 0) return; this.keys[this.keys.length] = u; this.units[u] = this.currentUnit; }
+    commitUnit(u: number) {
+        if (this.currentUnit.length === 0) return;
+        this.keys[this.keys.length] = u;
+        this.units[u] = this.currentUnit;
+    }
 
     getSet(): AtomSet {
         const sets: { [key: number]: OrderedSet } = Object.create(null);

+ 0 - 0
src/mol-data/model/common.ts


+ 0 - 0
src/mol-data/model/mmcif.ts


+ 8 - 7
src/mol-io/reader/cif/schema.ts

@@ -59,9 +59,10 @@ export namespace Field {
     export function vector(rows: number, spec?: Spec) { return createSchema(spec, Vector(rows)); }
     export function matrix(rows: number, cols: number, spec?: Spec) { return createSchema(spec, Matrix(rows, cols)); }
 
-    function create<T>(field: Data.Field, value: (row: number) => T, toArray: Column.Column<T>['toArray']): Column.Column<T> {
+    function create<T>(type: Column.ColumnType, field: Data.Field, value: (row: number) => T, toArray: Column.Column<T>['toArray']): Column.Column<T> {
         const presence = field.presence;
         return {
+            '@type': type,
             isDefined: field.isDefined,
             rowCount: field.rowCount,
             value,
@@ -76,23 +77,23 @@ export namespace Field {
         const pool = StringPool.create();
         const value = (row: number) => StringPool.get(pool, field.str(row));
         const array = (params?: Column.ToArrayParams) => Column.createAndFillArray(field.rowCount, value, params);
-        return create<string>(field, value, array);
+        return create<string>(Column.ColumnType.str, field, value, array);
     }
-    function Str(field: Data.Field) { return create(field, field.str, field.toStringArray); }
-    function Int(field: Data.Field) { return create(field, field.int, field.toIntArray); }
-    function Float(field: Data.Field) { return create(field, field.float, field.toFloatArray); }
+    function Str(field: Data.Field) { return create(Column.ColumnType.str, field, field.str, field.toStringArray); }
+    function Int(field: Data.Field) { return create(Column.ColumnType.int, field, field.int, field.toIntArray); }
+    function Float(field: Data.Field) { return create(Column.ColumnType.float, field, field.float, field.toFloatArray); }
 
     function Vector(rows: number) {
         return function(field: Data.Field, category: Data.Category, key: string) {
             const value = (row: number) => Data.getVector(category, key, rows, row);
-            return create(field, value, params => Column.createAndFillArray(field.rowCount, value, params));
+            return create(Column.ColumnType.vector, field, value, params => Column.createAndFillArray(field.rowCount, value, params));
         }
     }
 
     function Matrix(rows: number, cols: number) {
         return function(field: Data.Field, category: Data.Category, key: string) {
             const value = (row: number) => Data.getMatrix(category, key, rows, cols, row);
-            return create(field, value, params => Column.createAndFillArray(field.rowCount, value, params));
+            return create(Column.ColumnType.matrix, field, value, params => Column.createAndFillArray(field.rowCount, value, params));
         }
     }
 

+ 32 - 15
src/mol-io/reader/common/column.ts

@@ -4,13 +4,14 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-export type ColumnType = typeof ColumnType.str | typeof ColumnType.pooledStr | typeof ColumnType.int | typeof ColumnType.float
+export type ColumnType = typeof ColumnType.str | typeof ColumnType.int | typeof ColumnType.float | typeof ColumnType.vector | typeof ColumnType.matrix
 
 export namespace ColumnType {
-    export const str = { '@type': '' as string, kind: 'str' as 'str' };
-    export const pooledStr = { '@type': '' as string, kind: 'pooled-str' as 'pooled-str' };
-    export const int = { '@type': 0 as number, kind: 'int' as 'int' };
-    export const float = { '@type': 0 as number, kind: 'float' as 'float' };
+    export const str = { '@type': '' as string, kind: 'str' as 'str', isScalar: false };
+    export const int = { '@type': 0 as number, kind: 'int' as 'int', isScalar: true };
+    export const float = { '@type': 0 as number, kind: 'float' as 'float', isScalar: true };
+    export const vector = { '@type': [] as number[], kind: 'vector' as 'vector', isScalar: false };
+    export const matrix = { '@type': [] as number[][], kind: 'matrix' as 'matrix', isScalar: false };
 }
 
 export interface ToArrayParams {
@@ -22,6 +23,7 @@ export interface ToArrayParams {
 }
 
 export interface Column<T> {
+    readonly '@type': ColumnType,
     readonly isDefined: boolean,
     readonly rowCount: number,
     value(row: number): T,
@@ -34,6 +36,7 @@ export interface Column<T> {
 export function UndefinedColumn<T extends ColumnType>(rowCount: number, type: T): Column<T['@type']> {
     const value: Column<T['@type']>['value'] = type.kind === 'str' ? row => '' : row => 0;
     return {
+        '@type': type,
         isDefined: false,
         rowCount,
         value,
@@ -48,34 +51,48 @@ export function UndefinedColumn<T extends ColumnType>(rowCount: number, type: T)
     }
 }
 
-export function ArrayColumn<T>(array: ArrayLike<T>): Column<T> {
+export interface ArrayColumnSpec<T extends ColumnType> {
+    array: ArrayLike<T['@type']>,
+    type: T,
+    isValueDefined?: (row: number) => boolean
+}
+
+export function ArrayColumn<T extends ColumnType>({ array, type, isValueDefined }: ArrayColumnSpec<T>): Column<T['@type']> {
     const rowCount = array.length;
-    const value: Column<T>['value'] = row => array[row];
+    const value: Column<T['@type']>['value'] = row => array[row];
     const isTyped = isTypedArray(array);
     return {
-        isDefined: false,
+        '@type': type,
+        isDefined: true,
         rowCount,
         value,
-        isValueDefined: row => true,
+        isValueDefined: isValueDefined ? isValueDefined : row => true,
         toArray: isTyped
             ? params => typedArrayWindow(array, params) as any as ReadonlyArray<T>
             : params => {
                 const { start, end } = getArrayBounds(rowCount, params);
-                const ret = new Array(end - start);
+                if (start === 0 && end === array.length) return array as ReadonlyArray<T['@type']>;
+                const ret = new (params && typeof params.array !== 'undefined' ? params.array : (array as any).constructor)(end - start) as any;
                 for (let i = 0, _i = end - start; i < _i; i++) ret[i] = array[start + i];
                 return ret;
             },
         stringEquals: isTyped
             ? (row, value) => (array as any)[row] === +value
-            : (row, value) => {
-                const v = array[row];
-                if (typeof v !== 'string') return '' + v === value;
-                return v === value;
-            },
+            : type.kind === 'str'
+            ? (row, value) => array[row] === value
+            : type.isScalar
+            ? (row, value) => array[row] === '' + value
+            : (row, value) => false,
         areValuesEqual: (rowA, rowB) => array[rowA] === array[rowB]
     }
 }
 
+/** Makes the column backned by an array. Useful for columns that accessed often. */
+export function toArrayColumn<T>(c: Column<T>): Column<T> {
+    if (!c.isDefined) return UndefinedColumn(c.rowCount, c['@type']) as any as Column<T>;
+    return ArrayColumn({ array: c.toArray(), type: c['@type'] as any, isValueDefined: c.isValueDefined });
+}
+
 /** A helped function for Column.toArray */
 export function getArrayBounds(rowCount: number, params?: ToArrayParams) {
     const start = params && typeof params.start !== 'undefined' ? Math.max(Math.min(params.start, rowCount - 1), 0) : 0;