Skip to content
Snippets Groups Projects
Commit c5b1b84e authored by David Sehnal's avatar David Sehnal
Browse files

Data model improvements

parent c236b5d0
No related branches found
No related tags found
No related merge requests found
...@@ -60,9 +60,27 @@ export interface Field { ...@@ -60,9 +60,27 @@ export interface Field {
presence(row: number): ValuePresence, presence(row: number): ValuePresence,
areValuesEqual(rowA: number, rowB: number): boolean, areValuesEqual(rowA: number, rowB: number): boolean,
stringEquals(row: number, value: string | null): boolean, stringEquals(row: number, value: string): boolean,
toStringArray(ctor?: (size: number) => Column.ArrayType, startRow?: number, endRowExclusive?: number): ReadonlyArray<string>, toStringArray(params?: Column.ToArrayParams): ReadonlyArray<string>,
toIntArray(ctor?: (size: number) => Column.ArrayType, startRow?: number, endRowExclusive?: number): ReadonlyArray<number>, toIntArray(params?: Column.ToArrayParams): ReadonlyArray<number>,
toFloatArray(ctor?: (size: number) => Column.ArrayType, startRow?: number, endRowExclusive?: number): ReadonlyArray<number> toFloatArray(params?: Column.ToArrayParams): ReadonlyArray<number>
}
export function DefaultUndefinedField(rowCount: number): Field {
return {
isDefined: false,
rowCount,
str: row => '',
int: row => 0,
float: row => 0,
presence: row => ValuePresence.NotSpecified,
areValuesEqual: (rowA, rowB) => true,
stringEquals: (row, value) => value === null,
toStringArray: (p) => Column.createArray(rowCount, p).array,
toIntArray: (p) => Column.createArray(rowCount, p).array,
toFloatArray: (p) => Column.createArray(rowCount, p).array
};
} }
\ No newline at end of file
...@@ -48,55 +48,45 @@ export type Category<Fields> = Fields & { ...@@ -48,55 +48,45 @@ export type Category<Fields> = Fields & {
export namespace Category { export namespace Category {
export type Schema = { '@alias'?: string } & { [field: string]: Field.Schema<any> } export type Schema = { '@alias'?: string } & { [field: string]: Field.Schema<any> }
export type Instance<T extends Schema> = Category<{ [F in keyof T]: Field<T[F]['type']> }> export type Instance<T extends Schema> = Category<{ [F in keyof T]: Column.Column<T[F]['type']> }>
} }
export interface Field<T> { // export interface Field<T> {
readonly isDefined: boolean, // readonly isDefined: boolean,
value(row: number): T, // value(row: number): T,
presence(row: number): Data.ValuePresence, // presence(row: number): Data.ValuePresence,
areValuesEqual(rowA: number, rowB: number): boolean, // areValuesEqual(rowA: number, rowB: number): boolean,
stringEquals(row: number, value: string | null): boolean, // stringEquals(row: number, value: string | null): boolean,
/** Converts the selected row range to an array. ctor might or might not be called depedning on the source data format. */ // /** Converts the selected row range to an array. ctor might or might not be called depedning on the source data format. */
toArray(ctor?: (size: number) => Column.ArrayType, startRow?: number, endRowExclusive?: number): ReadonlyArray<T> | undefined // toArray(params?: Column.ToArrayParams): ReadonlyArray<T>
} // }
export namespace Field { export namespace Field {
export interface Schema<T> { type: T, ctor: (field: Data.Field) => Field<T>, undefinedField: (c: number) => Data.Field, alias?: string }; export interface Schema<T> { type: T, ctor: (field: Data.Field) => Column.Column<T>, undefinedField: (c: number) => Data.Field, alias?: string };
export interface Spec { undefinedField?: (c: number) => Data.Field, alias?: string } export interface Spec { undefinedField?: (c: number) => Data.Field, alias?: string }
export function str(spec?: Spec) { return createSchema(spec, Str); } export function str(spec?: Spec) { return createSchema(spec, Str); }
export function int(spec?: Spec) { return createSchema(spec, Int); } export function int(spec?: Spec) { return createSchema(spec, Int); }
export function float(spec?: Spec) { return createSchema(spec, Float); } export function float(spec?: Spec) { return createSchema(spec, Float); }
function create<T>(field: Data.Field, value: (row: number) => T, toArray: Field<T>['toArray']): Field<T> { function create<T>(field: Data.Field, value: (row: number) => T, toArray: Column.Column<T>['toArray']): Column.Column<T> {
return { isDefined: field.isDefined, value, presence: field.presence, areValuesEqual: field.areValuesEqual, stringEquals: field.stringEquals, toArray }; const presence = field.presence;
return {
isDefined: field.isDefined,
rowCount: field.rowCount,
value,
isValueDefined: row => presence(row) === Data.ValuePresence.Present,
areValuesEqual: field.areValuesEqual,
toArray
};
} }
function Str(field: Data.Field) { return create(field, field.str, field.toStringArray); } 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 Int(field: Data.Field) { return create(field, field.int, field.toIntArray); }
function Float(field: Data.Field) { return create(field, field.float, field.toFloatArray); } function Float(field: Data.Field) { return create(field, field.float, field.toFloatArray); }
function defaultUndefined(rowCount: number): Data.Field { function createSchema<T>(spec: Spec | undefined, ctor: (field: Data.Field) => Column.Column<T>): Schema<T> {
return { return { type: 0 as any, ctor, undefinedField: (spec && spec.undefinedField) || Data.DefaultUndefinedField, alias: spec && spec.alias };
isDefined: false,
rowCount,
str: row => '',
int: row => 0,
float: row => 0,
presence: row => Data.ValuePresence.NotSpecified,
areValuesEqual: (rowA, rowB) => true,
stringEquals: (row, value) => value === null,
toStringArray: (ctor, s, e) => Column.createArray(rowCount, ctor, s, e).array,
toIntArray: (ctor, s, e) => Column.createArray(rowCount, ctor, s, e).array,
toFloatArray: (ctor, s, e) => Column.createArray(rowCount, ctor, s, e).array
};
}
function createSchema<T>(spec: Spec | undefined, ctor: (field: Data.Field) => Field<T>): Schema<T> {
return { type: 0 as any, ctor, undefinedField: (spec && spec.undefinedField) || defaultUndefined, alias: spec && spec.alias };
} }
} }
......
...@@ -42,7 +42,7 @@ export default function CifTextField(data: string, tokens: ArrayLike<number>, ro ...@@ -42,7 +42,7 @@ export default function CifTextField(data: string, tokens: ArrayLike<number>, ro
int, int,
float, float,
presence, presence,
areValuesEqual: (rowA, rowB) => { areValuesEqual(rowA, rowB) {
const aS = tokens[2 * rowA], bS = tokens[2 * rowB]; const aS = tokens[2 * rowA], bS = tokens[2 * rowB];
const len = tokens[2 * rowA + 1] - aS; const len = tokens[2 * rowA + 1] - aS;
if (len !== tokens[2 * rowB + 1] - bS) return false; if (len !== tokens[2 * rowB + 1] - bS) return false;
...@@ -53,7 +53,7 @@ export default function CifTextField(data: string, tokens: ArrayLike<number>, ro ...@@ -53,7 +53,7 @@ export default function CifTextField(data: string, tokens: ArrayLike<number>, ro
} }
return true; return true;
}, },
stringEquals: (row, value) => { stringEquals(row, value) {
const s = tokens[2 * row]; const s = tokens[2 * row];
if (!value) return presence(row) !== Data.ValuePresence.Present; if (!value) return presence(row) !== Data.ValuePresence.Present;
const len = value.length; const len = value.length;
...@@ -63,16 +63,16 @@ export default function CifTextField(data: string, tokens: ArrayLike<number>, ro ...@@ -63,16 +63,16 @@ export default function CifTextField(data: string, tokens: ArrayLike<number>, ro
} }
return true; return true;
}, },
toStringArray: (ctor, s, e) => { toStringArray(params) {
const { array, start } = Column.createArray(rowCount, ctor, s, e); const { array, start } = Column.createArray(rowCount, params);
return fillArrayValues(str, array, start); return fillArrayValues(str, array, start);
}, },
toIntArray: (ctor, s, e) => { toIntArray(params) {
const { array, start } = Column.createArray(rowCount, ctor, s, e); const { array, start } = Column.createArray(rowCount, params);
return fillArrayValues(int, array, start); return fillArrayValues(int, array, start);
}, },
toFloatArray: (ctor, s, e) => { toFloatArray(params) {
const { array, start } = Column.createArray(rowCount, ctor, s, e); const { array, start } = Column.createArray(rowCount, params);
return fillArrayValues(float, array, start); return fillArrayValues(float, array, start);
} }
} }
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
* @author David Sehnal <david.sehnal@gmail.com> * @author David Sehnal <david.sehnal@gmail.com>
*/ */
export type ArrayType = string[] | number[] | Float32Array | Float64Array | Int8Array | Int16Array | Int32Array | Uint8Array | Uint16Array | Uint32Array
export type ColumnType = typeof ColumnType.str | typeof ColumnType.pooledStr | typeof ColumnType.int | typeof ColumnType.float export type ColumnType = typeof ColumnType.str | typeof ColumnType.pooledStr | typeof ColumnType.int | typeof ColumnType.float
export namespace ColumnType { export namespace ColumnType {
...@@ -14,11 +13,21 @@ export namespace ColumnType { ...@@ -14,11 +13,21 @@ export namespace ColumnType {
export const float = { '@type': 0 as number, kind: 'float' as 'float' }; export const float = { '@type': 0 as number, kind: 'float' as 'float' };
} }
export interface ToArrayParams {
array?: { new(size: number): ArrayLike<number> },
/** First row */
start?: number,
/** Last row (exclusive) */
end?: number
}
export interface Column<T> { export interface Column<T> {
readonly isDefined: boolean, readonly isDefined: boolean,
readonly rowCount: number, readonly rowCount: number,
value(row: number): T, value(row: number): T,
toArray(ctor?: (size: number) => ArrayType, startRow?: number, endRowExclusive?: number): ReadonlyArray<T> isValueDefined(row: number): boolean,
toArray(params?: ToArrayParams): ReadonlyArray<T>,
areValuesEqual(rowA: number, rowB: number): boolean
} }
export function UndefinedColumn<T extends ColumnType>(rowCount: number, type: T): Column<T['@type']> { export function UndefinedColumn<T extends ColumnType>(rowCount: number, type: T): Column<T['@type']> {
...@@ -27,18 +36,21 @@ export function UndefinedColumn<T extends ColumnType>(rowCount: number, type: T) ...@@ -27,18 +36,21 @@ export function UndefinedColumn<T extends ColumnType>(rowCount: number, type: T)
isDefined: false, isDefined: false,
rowCount, rowCount,
value, value,
toArray(ctor, s, e) { isValueDefined(row) { return false; },
const { array } = createArray(rowCount, ctor, s, e); toArray(params) {
const { array } = createArray(rowCount, params);
for (let i = 0, _i = array.length; i < _i; i++) array[i] = value(0) for (let i = 0, _i = array.length; i < _i; i++) array[i] = value(0)
return array; return array;
} },
areValuesEqual() { return true; }
} }
} }
/** A helped function for Column.toArray */ /** A helped function for Column.toArray */
export function createArray(rowCount: number, ctor?: (size: number) => ArrayType, start?: number, end?: number) { export function createArray(rowCount: number, params?: ToArrayParams) {
const c = typeof ctor !== 'undefined' ? ctor : (s: number) => new Array(s); const { array, start, end } = params || ({} as ToArrayParams);
const c = typeof array !== 'undefined' ? array : Array;
const s = typeof start !== 'undefined' ? Math.max(Math.min(start, rowCount - 1), 0) : 0; const s = typeof start !== 'undefined' ? Math.max(Math.min(start, rowCount - 1), 0) : 0;
const e = typeof end !== 'undefined' ? Math.min(end, rowCount) : rowCount; const e = typeof end !== 'undefined' ? Math.min(end, rowCount) : rowCount;
return { array: c(e - s) as any[], start: s, end: e }; return { array: new c(e - s) as any[], start: s, end: e };
} }
\ No newline at end of file
...@@ -5,19 +5,13 @@ ...@@ -5,19 +5,13 @@
*/ */
import { Column, ColumnType, createArray } from '../../column' import { Column, ColumnType, createArray } from '../../column'
import { trimStr } from '../tokenizer' import { trimStr, Lines } from '../tokenizer'
import { parseIntSkipLeadingWhitespace, parseFloatSkipLeadingWhitespace } from '../number-parser' import { parseIntSkipLeadingWhitespace, parseFloatSkipLeadingWhitespace } from '../number-parser'
import StringPool from '../../../../utils/short-string-pool' import StringPool from '../../../../utils/short-string-pool'
export interface FixedColumnInfo { export default function FixedColumnProvider(lines: Lines) {
data: string,
lines: ArrayLike<number>,
rowCount: number
}
export default function FixedColumnProvider(info: FixedColumnInfo) {
return function<T extends ColumnType>(offset: number, width: number, type: T) { return function<T extends ColumnType>(offset: number, width: number, type: T) {
return FixedColumn(info, offset, width, type); return FixedColumn(lines, offset, width, type);
} }
} }
...@@ -26,39 +20,43 @@ function fillArrayValues(value: (row: number) => any, target: any[], start: numb ...@@ -26,39 +20,43 @@ function fillArrayValues(value: (row: number) => any, target: any[], start: numb
return target; return target;
} }
export function FixedColumn<T extends ColumnType>(info: FixedColumnInfo, offset: number, width: number, type: T): Column<T['@type']> { export function FixedColumn<T extends ColumnType>(lines: Lines, offset: number, width: number, type: T): Column<T['@type']> {
const { data, lines, rowCount } = info; const { data, tokens, count: rowCount } = lines;
const { kind } = type; const { kind } = type;
const pool = kind === 'pooled-str' ? StringPool.create() : void 0; const pool = kind === 'pooled-str' ? StringPool.create() : void 0;
const value: Column<T['@type']>['value'] = kind === 'str' ? row => { const value: Column<T['@type']>['value'] = kind === 'str' ? row => {
let s = lines[2 * row] + offset, le = lines[2 * row + 1]; let s = tokens[2 * row] + offset, le = tokens[2 * row + 1];
if (s >= le) return ''; if (s >= le) return '';
let e = s + width; let e = s + width;
if (e > le) e = le; if (e > le) e = le;
return trimStr(data, s, e); return trimStr(data, s, e);
} : kind === 'pooled-str' ? row => { } : kind === 'pooled-str' ? row => {
let s = lines[2 * row] + offset, le = lines[2 * row + 1]; let s = tokens[2 * row] + offset, le = tokens[2 * row + 1];
if (s >= le) return ''; if (s >= le) return '';
let e = s + width; let e = s + width;
if (e > le) e = le; if (e > le) e = le;
return StringPool.get(pool!, trimStr(data, s, e)); return StringPool.get(pool!, trimStr(data, s, e));
} : kind === 'int' ? row => { } : kind === 'int' ? row => {
const s = lines[2 * row] + offset; const s = tokens[2 * row] + offset;
if (s > lines[2 * row + 1]) return 0; if (s > tokens[2 * row + 1]) return 0;
return parseIntSkipLeadingWhitespace(data, s, s + width); return parseIntSkipLeadingWhitespace(data, s, s + width);
} : row => { } : row => {
const s = lines[2 * row] + offset; const s = tokens[2 * row] + offset;
if (s > lines[2 * row + 1]) return 0; if (s > tokens[2 * row + 1]) return 0;
return parseFloatSkipLeadingWhitespace(data, s, s + width); return parseFloatSkipLeadingWhitespace(data, s, s + width);
}; };
return { return {
isDefined: true, isDefined: true,
rowCount, rowCount,
value, value,
toArray(ctor, s, e) { isValueDefined(row) { return true; },
const { array, start } = createArray(rowCount, ctor, s, e); toArray(params) {
const { array, start } = createArray(rowCount, params);
return fillArrayValues(value, array, start); return fillArrayValues(value, array, start);
},
areValuesEqual(rowA, rowB) {
return value(rowA) === value(rowB);
} }
}; };
} }
\ No newline at end of file
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* @author Alexander Rose <alexander.rose@weirdbyte.de> * @author Alexander Rose <alexander.rose@weirdbyte.de>
*/ */
export interface State<TokenType = any> { export interface Tokenizer {
data: string data: string
position: number position: number
...@@ -15,132 +15,150 @@ export interface State<TokenType = any> { ...@@ -15,132 +15,150 @@ export interface State<TokenType = any> {
currentLineNumber: number currentLineNumber: number
currentTokenStart: number currentTokenStart: number
currentTokenEnd: number currentTokenEnd: number
}
currentTokenType: TokenType export interface Lines {
data: string,
count: number,
tokens: ArrayLike<number>
} }
export function State<TokenType>(data: string, initialTokenType?: TokenType): State<TokenType> { export function Tokenizer(data: string): Tokenizer {
return { return {
data, data,
position: 0, position: 0,
length: data.length, length: data.length,
currentLineNumber: 1, currentLineNumber: 1,
currentTokenStart: 0, currentTokenStart: 0,
currentTokenEnd: 0, currentTokenEnd: 0
currentTokenType: initialTokenType!
}; };
} }
export function getTokenString(state: State) { export namespace Tokenizer {
return state.data.substring(state.currentTokenStart, state.currentTokenEnd);
}
/** export function getTokenString(state: Tokenizer) {
* Eat everything until a newline occurs. return state.data.substring(state.currentTokenStart, state.currentTokenEnd);
*/ }
export function eatLine(state: State) {
const { data } = state; /**
while (state.position < state.length) { * Eat everything until a newline occurs.
switch (data.charCodeAt(state.position)) { */
case 10: // \n export function eatLine(state: Tokenizer) {
state.currentTokenEnd = state.position; const { data } = state;
++state.position; while (state.position < state.length) {
++state.currentLineNumber; switch (data.charCodeAt(state.position)) {
return; case 10: // \n
case 13: // \r state.currentTokenEnd = state.position;
state.currentTokenEnd = state.position; ++state.position;
++state.position; ++state.currentLineNumber;
++state.currentLineNumber; return;
if (data.charCodeAt(state.position) === 10) { case 13: // \r
state.currentTokenEnd = state.position;
++state.position;
++state.currentLineNumber;
if (data.charCodeAt(state.position) === 10) {
++state.position;
}
return;
default:
++state.position; ++state.position;
} break;
return; }
default:
++state.position;
break;
} }
state.currentTokenEnd = state.position;
} }
state.currentTokenEnd = state.position;
}
/** Sets the current token start to the current position */ /** Sets the current token start to the current position */
export function markStart(state: State) { export function markStart(state: Tokenizer) {
state.currentTokenStart = state.position; state.currentTokenStart = state.position;
} }
/** Sets the current token start to current position and moves to the next line. */ /** Sets the current token start to current position and moves to the next line. */
export function markLine(state: State) { export function markLine(state: Tokenizer) {
state.currentTokenStart = state.position; state.currentTokenStart = state.position;
eatLine(state); eatLine(state);
} }
/** /** Advance the state by the given number of lines and return line starts/ends as tokens. */
* Eat everything until a whitespace/newline occurs. export function readLines(state: Tokenizer, count: number): Lines {
*/ const lineTokens = Tokens.create(count * 2);
export function eatValue(state: State) {
while (state.position < state.length) { for (let i = 0; i < count; i++) {
switch (state.data.charCodeAt(state.position)) { markLine(state);
case 9: // \t Tokens.addUnchecked(lineTokens, state.currentTokenStart, state.currentTokenEnd);
case 10: // \n }
case 13: // \r
case 32: // ' ' return { data: state.data, count, tokens: lineTokens.indices };
state.currentTokenEnd = state.position; }
return;
default: /**
++state.position; * Eat everything until a whitespace/newline occurs.
break; */
export function eatValue(state: Tokenizer) {
while (state.position < state.length) {
switch (state.data.charCodeAt(state.position)) {
case 9: // \t
case 10: // \n
case 13: // \r
case 32: // ' '
state.currentTokenEnd = state.position;
return;
default:
++state.position;
break;
}
} }
state.currentTokenEnd = state.position;
} }
state.currentTokenEnd = state.position;
}
/** /**
* Skips all the whitespace - space, tab, newline, CR * Skips all the whitespace - space, tab, newline, CR
* Handles incrementing line count. * Handles incrementing line count.
*/ */
export function skipWhitespace(state: State): number { export function skipWhitespace(state: Tokenizer): number {
let prev = 10; let prev = 10;
while (state.position < state.length) { while (state.position < state.length) {
let c = state.data.charCodeAt(state.position); let c = state.data.charCodeAt(state.position);
switch (c) { switch (c) {
case 9: // '\t' case 9: // '\t'
case 32: // ' ' case 32: // ' '
prev = c; prev = c;
++state.position; ++state.position;
break; break;
case 10: // \n case 10: // \n
// handle \r\n // handle \r\n
if (prev !== 13) { if (prev !== 13) {
++state.currentLineNumber;
}
prev = c;
++state.position;
break;
case 13: // \r
prev = c;
++state.position;
++state.currentLineNumber; ++state.currentLineNumber;
} break;
prev = c; default:
++state.position; return prev;
break; }
case 13: // \r
prev = c;
++state.position;
++state.currentLineNumber;
break;
default:
return prev;
} }
return prev;
} }
return prev;
}
/** Trims spaces and tabs */ /** Trims spaces and tabs */
export function trim(state: State, start: number, end: number) { export function trim(state: Tokenizer, start: number, end: number) {
const { data } = state; const { data } = state;
let s = start, e = end - 1; let s = start, e = end - 1;
let c = data.charCodeAt(s); let c = data.charCodeAt(s);
while ((c === 9 || c === 32) && s <= e) c = data.charCodeAt(++s); while ((c === 9 || c === 32) && s <= e) c = data.charCodeAt(++s);
c = data.charCodeAt(e); c = data.charCodeAt(e);
while ((c === 9 || c === 32) && e >= s) c = data.charCodeAt(--e); while ((c === 9 || c === 32) && e >= s) c = data.charCodeAt(--e);
state.currentTokenStart = s; state.currentTokenStart = s;
state.currentTokenEnd = e + 1; state.currentTokenEnd = e + 1;
state.position = end; state.position = end;
}
} }
export function trimStr(data: string, start: number, end: number) { export function trimStr(data: string, start: number, end: number) {
...@@ -189,8 +207,4 @@ export namespace Tokens { ...@@ -189,8 +207,4 @@ export namespace Tokens {
} }
} }
export default Tokenizer
/** \ No newline at end of file
* A helper for building a typed array of token indices.
*/
export default Tokens
\ No newline at end of file
...@@ -5,14 +5,14 @@ ...@@ -5,14 +5,14 @@
* @author David Sehnal <david.sehnal@gmail.com> * @author David Sehnal <david.sehnal@gmail.com>
*/ */
import { State as TokenizerState, Tokens, markLine, getTokenString } from '../common/text/tokenizer' import Tokenizer from '../common/text/tokenizer'
import FixedColumn from '../common/text/column/fixed' import FixedColumn from '../common/text/column/fixed'
import { ColumnType, UndefinedColumn } from '../common/column' import { ColumnType, UndefinedColumn } from '../common/column'
import * as Schema from './schema' import * as Schema from './schema'
import Result from '../result' import Result from '../result'
interface State { interface State {
tokenizer: TokenizerState, tokenizer: Tokenizer,
header: Schema.Header, header: Schema.Header,
numberOfAtoms: number, numberOfAtoms: number,
} }
...@@ -27,7 +27,7 @@ function createEmptyHeader(): Schema.Header { ...@@ -27,7 +27,7 @@ function createEmptyHeader(): Schema.Header {
}; };
} }
function createState(tokenizer: TokenizerState): State { function State(tokenizer: Tokenizer): State {
return { return {
tokenizer, tokenizer,
header: createEmptyHeader(), header: createEmptyHeader(),
...@@ -40,14 +40,14 @@ function createState(tokenizer: TokenizerState): State { ...@@ -40,14 +40,14 @@ function createState(tokenizer: TokenizerState): State {
*/ */
function handleTitleString(state: State) { function handleTitleString(state: State) {
const { tokenizer, header } = state; const { tokenizer, header } = state;
markLine(tokenizer); Tokenizer.markLine(tokenizer);
let line = getTokenString(tokenizer); let line = Tokenizer.getTokenString(tokenizer);
// skip potential empty lines... // skip potential empty lines...
if (line.trim().length === 0) { if (line.trim().length === 0) {
markLine(tokenizer); Tokenizer.markLine(tokenizer);
line = getTokenString(tokenizer); line = Tokenizer.getTokenString(tokenizer);
} }
const timeOffset = line.lastIndexOf('t='); const timeOffset = line.lastIndexOf('t=');
...@@ -67,8 +67,8 @@ function handleTitleString(state: State) { ...@@ -67,8 +67,8 @@ function handleTitleString(state: State) {
*/ */
function handleNumberOfAtoms(state: State) { function handleNumberOfAtoms(state: State) {
const { tokenizer } = state; const { tokenizer } = state;
markLine(tokenizer); Tokenizer.markLine(tokenizer);
const line = getTokenString(tokenizer); const line = Tokenizer.getTokenString(tokenizer);
state.numberOfAtoms = parseInt(line); state.numberOfAtoms = parseInt(line);
} }
...@@ -90,17 +90,12 @@ function handleNumberOfAtoms(state: State) { ...@@ -90,17 +90,12 @@ function handleNumberOfAtoms(state: State) {
*/ */
function handleAtoms(state: State): Schema.Atoms { function handleAtoms(state: State): Schema.Atoms {
const { tokenizer, numberOfAtoms } = state; const { tokenizer, numberOfAtoms } = state;
const lineTokens = Tokens.create(numberOfAtoms * 2); const lines = Tokenizer.readLines(tokenizer, numberOfAtoms);
for (let i = 0; i < numberOfAtoms; i++) { const positionSample = tokenizer.data.substring(lines.tokens[0], lines.tokens[1]).substring(20);
markLine(tokenizer);
Tokens.addUnchecked(lineTokens, tokenizer.currentTokenStart, tokenizer.currentTokenEnd);
}
const lines = lineTokens.indices;
const positionSample = tokenizer.data.substring(lines[0], lines[1]).substring(20);
const precisions = positionSample.match(/\.\d+/g)!; const precisions = positionSample.match(/\.\d+/g)!;
const hasVelocities = precisions.length === 6; const hasVelocities = precisions.length === 6;
state.header.hasVelocities = hasVelocities; state.header.hasVelocities = hasVelocities;
state.header.precision.position = precisions[0].length - 1; state.header.precision.position = precisions[0].length - 1;
state.header.precision.velocity = hasVelocities ? precisions[3].length - 1 : 0; state.header.precision.velocity = hasVelocities ? precisions[3].length - 1 : 0;
...@@ -110,7 +105,7 @@ function handleAtoms(state: State): Schema.Atoms { ...@@ -110,7 +105,7 @@ function handleAtoms(state: State): Schema.Atoms {
const vO = pO + 3 * pW; const vO = pO + 3 * pW;
const vW = state.header.precision.velocity + 4; const vW = state.header.precision.velocity + 4;
const col = FixedColumn({ data: tokenizer.data, lines, rowCount: state.numberOfAtoms }); const col = FixedColumn(lines);
const undef = UndefinedColumn(state.numberOfAtoms, ColumnType.float); const undef = UndefinedColumn(state.numberOfAtoms, ColumnType.float);
const ret = { const ret = {
...@@ -138,17 +133,17 @@ function handleAtoms(state: State): Schema.Atoms { ...@@ -138,17 +133,17 @@ function handleAtoms(state: State): Schema.Atoms {
*/ */
function handleBoxVectors(state: State) { function handleBoxVectors(state: State) {
const { tokenizer } = state; const { tokenizer } = state;
markLine(tokenizer); Tokenizer.markLine(tokenizer);
const values = getTokenString(tokenizer).trim().split(/\s+/g); const values = Tokenizer.getTokenString(tokenizer).trim().split(/\s+/g);
state.header.box = [+values[0], +values[1], +values[2]]; state.header.box = [+values[0], +values[1], +values[2]];
} }
function parseInternal(data: string): Result<Schema.File> { function parseInternal(data: string): Result<Schema.File> {
const tokenizer = TokenizerState(data); const tokenizer = Tokenizer(data);
const structures: Schema.Structure[] = []; const structures: Schema.Structure[] = [];
while (tokenizer.position < data.length) { while (tokenizer.position < data.length) {
const state = createState(tokenizer); const state = State(tokenizer);
handleTitleString(state); handleTitleString(state);
handleNumberOfAtoms(state); handleNumberOfAtoms(state);
const atoms = handleAtoms(state); const atoms = handleAtoms(state);
......
...@@ -34,7 +34,7 @@ describe('schema', () => { ...@@ -34,7 +34,7 @@ describe('schema', () => {
}); });
it('toArray', () => { it('toArray', () => {
const ret = data.atoms.x.toArray(s => new Int32Array(s))!; const ret = data.atoms.x.toArray({ array: Int32Array });
expect(ret.length).toBe(3); expect(ret.length).toBe(3);
expect(ret[0]).toBe(1); expect(ret[0]).toBe(1);
expect(ret[1]).toBe(2); expect(ret[1]).toBe(2);
......
...@@ -30,7 +30,7 @@ const linesTokens = (function () { ...@@ -30,7 +30,7 @@ const linesTokens = (function () {
}()); }());
describe('fixed text column', () => { describe('fixed text column', () => {
const col = FixedColumn({ data, lines: linesTokens, rowCount: lines.length }); const col = FixedColumn({ data, tokens: linesTokens, count: lines.length });
const col1 = col(0, 5, ColumnType.float); const col1 = col(0, 5, ColumnType.float);
const col2 = col(5, 4, ColumnType.str); const col2 = col(5, 4, ColumnType.str);
it('number', () => { it('number', () => {
......
...@@ -51,22 +51,22 @@ export function _gro() { ...@@ -51,22 +51,22 @@ export function _gro() {
console.log('rowCount', n) console.log('rowCount', n)
console.time('getFloatArray x') console.time('getFloatArray x')
const x = atoms.x.toArray(x => new Float32Array(x))! const x = atoms.x.toArray({ array: Float32Array })
console.timeEnd('getFloatArray x') console.timeEnd('getFloatArray x')
console.log(x.length, x[0], x[x.length - 1]) console.log(x.length, x[0], x[x.length - 1])
console.time('getFloatArray y') console.time('getFloatArray y')
const y = atoms.y.toArray(x => new Float32Array(x))! const y = atoms.y.toArray({ array: Float32Array })
console.timeEnd('getFloatArray y') console.timeEnd('getFloatArray y')
console.log(y.length, y[0], y[y.length - 1]) console.log(y.length, y[0], y[y.length - 1])
console.time('getFloatArray z') console.time('getFloatArray z')
const z = atoms.z.toArray(x => new Float32Array(x))! const z = atoms.z.toArray({ array: Float32Array })
console.timeEnd('getFloatArray z') console.timeEnd('getFloatArray z')
console.log(z.length, z[0], z[z.length - 1]) console.log(z.length, z[0], z[z.length - 1])
console.time('getIntArray residueNumber') console.time('getIntArray residueNumber')
const residueNumber = atoms.residueNumber.toArray(x => new Int32Array(x))! const residueNumber = atoms.residueNumber.toArray({ array: Int32Array })
console.timeEnd('getIntArray residueNumber') console.timeEnd('getIntArray residueNumber')
console.log(residueNumber.length, residueNumber[0], residueNumber[residueNumber.length - 1]) console.log(residueNumber.length, residueNumber[0], residueNumber[residueNumber.length - 1])
}); });
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment