From b4b329bea554c71ca8d5dc27b88069f70e55e78c Mon Sep 17 00:00:00 2001 From: David Sehnal <david.sehnal@gmail.com> Date: Thu, 26 Oct 2017 12:55:52 +0200 Subject: [PATCH] ArrayColumn --- src/mol-data/atom-set/builder.ts | 6 +++- src/mol-data/model/common.ts | 0 src/mol-data/model/mmcif.ts | 0 src/mol-io/reader/cif/schema.ts | 15 +++++----- src/mol-io/reader/common/column.ts | 47 ++++++++++++++++++++---------- 5 files changed, 45 insertions(+), 23 deletions(-) create mode 100644 src/mol-data/model/common.ts create mode 100644 src/mol-data/model/mmcif.ts diff --git a/src/mol-data/atom-set/builder.ts b/src/mol-data/atom-set/builder.ts index 016dad1df..2dea68470 100644 --- a/src/mol-data/atom-set/builder.ts +++ b/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); diff --git a/src/mol-data/model/common.ts b/src/mol-data/model/common.ts new file mode 100644 index 000000000..e69de29bb diff --git a/src/mol-data/model/mmcif.ts b/src/mol-data/model/mmcif.ts new file mode 100644 index 000000000..e69de29bb diff --git a/src/mol-io/reader/cif/schema.ts b/src/mol-io/reader/cif/schema.ts index 4723e404e..67f173f0b 100644 --- a/src/mol-io/reader/cif/schema.ts +++ b/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)); } } diff --git a/src/mol-io/reader/common/column.ts b/src/mol-io/reader/common/column.ts index 13dc3f2ba..2e0ffcf48 100644 --- a/src/mol-io/reader/common/column.ts +++ b/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; -- GitLab