diff --git a/src/reader/cif/binary/field.ts b/src/reader/cif/binary/field.ts index 4d668b5817e24d1fa776467bb58844f9912183d1..d5d5ff891e0b6a90b9e06be82e6eeb90764eba3a 100644 --- a/src/reader/cif/binary/field.ts +++ b/src/reader/cif/binary/field.ts @@ -8,12 +8,13 @@ import * as Column from '../../common/column' import * as Data from '../data-model' import { EncodedColumn } from './encoding' import decode from './decoder' +import { isTypedArray, typedArrayWindow } from '../../common/binary/column' import { parseInt as fastParseInt, parseFloat as fastParseFloat } from '../../common/text/number-parser' export default function Field(column: EncodedColumn): Data.Field { const mask = column.mask ? decode(column.mask) as number[] : void 0; const data = decode(column.data); - const isNumeric = (data as any).buffer && (data as any).byteLength && (data as any).BYTES_PER_ELEMENT; + const isNumeric = isTypedArray(data); const str: Data.Field['str'] = isNumeric ? mask @@ -45,9 +46,13 @@ export default function Field(column: EncodedColumn): Data.Field { float, presence, areValuesEqual: (rowA, rowB) => data[rowA] === data[rowB], - stringEquals(row, v) { return str(row) === v; }, - toStringArray(params) { return Column.createAndFillArray(rowCount, str, params); }, - toIntArray(params) { return Column.createAndFillArray(rowCount, int, params); }, - toFloatArray(params) { return Column.createAndFillArray(rowCount, float, params); } + stringEquals: (row, v) => str(row) === v, + toStringArray: params => Column.createAndFillArray(rowCount, str, params), + toIntArray: isNumeric + ? params => typedArrayWindow(data, params) + : params => Column.createAndFillArray(rowCount, int, params), + toFloatArray: isNumeric + ? params => typedArrayWindow(data, params) + : params => Column.createAndFillArray(rowCount, float, params) }; } \ No newline at end of file diff --git a/src/reader/cif/text/field.ts b/src/reader/cif/text/field.ts index ecf14c3618d7a49c493c34bbcc89a7054c13ada6..2e09cd1b0cf369ac0d4cef3346d7d2fb88aad4e9 100644 --- a/src/reader/cif/text/field.ts +++ b/src/reader/cif/text/field.ts @@ -44,7 +44,7 @@ export default function CifTextField(tokens: Tokens, rowCount: number): Data.Fie float, presence, areValuesEqual: TokenColumn.areValuesEqualProvider(tokens), - stringEquals(row, v) { + stringEquals: (row, v) => { const s = indices[2 * row]; const value = v || ''; if (!value && presence(row) !== Data.ValuePresence.Present) return true; @@ -55,8 +55,8 @@ export default function CifTextField(tokens: Tokens, rowCount: number): Data.Fie } return true; }, - toStringArray(params) { return Column.createAndFillArray(rowCount, str, params); }, - toIntArray(params) { return Column.createAndFillArray(rowCount, int, params); }, - toFloatArray(params) { return Column.createAndFillArray(rowCount, float, params); } + toStringArray: params => Column.createAndFillArray(rowCount, str, params), + toIntArray: params => Column.createAndFillArray(rowCount, int, params), + toFloatArray: params => Column.createAndFillArray(rowCount, float, params) } } \ No newline at end of file diff --git a/src/reader/common/binary/column.ts b/src/reader/common/binary/column.ts new file mode 100644 index 0000000000000000000000000000000000000000..e2b3274a52abf5a7c1799db3a3f5af9ff24341da --- /dev/null +++ b/src/reader/common/binary/column.ts @@ -0,0 +1,18 @@ +/** + * Copyright (c) 2017 molio contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + */ + +import { getArrayBounds, ToArrayParams } from '../column' + +export function isTypedArray(data: any) { + return data.buffer && typeof data.byteLength === 'number' && data.BYTES_PER_ELEMENT; +} + +export function typedArrayWindow(data: any, params?: ToArrayParams): ArrayLike<number> { + const { constructor, buffer, length, byteOffset, BYTES_PER_ELEMENT } = data; + const { start, end } = getArrayBounds(length, params); + if (start === 0 && end === length) return data; + return new constructor(buffer, byteOffset + BYTES_PER_ELEMENT * start, Math.min(length, end - start)); +} \ No newline at end of file diff --git a/src/reader/common/column.ts b/src/reader/common/column.ts index 209d47961bea83d612566d7f001a8356d5c18ff3..fc8ca58d1f8f46068cd1e244969c4021e5492028 100644 --- a/src/reader/common/column.ts +++ b/src/reader/common/column.ts @@ -48,13 +48,18 @@ export function UndefinedColumn<T extends ColumnType>(rowCount: number, type: T) } } +/** 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; + const end = params && typeof params.end !== 'undefined' ? Math.min(params.end, rowCount) : rowCount; + return { start, end }; +} + /** A helped function for Column.toArray */ export function createArray(rowCount: number, params?: ToArrayParams) { - 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 e = typeof end !== 'undefined' ? Math.min(end, rowCount) : rowCount; - return { array: new c(e - s) as any[], start: s, end: e }; + const c = params && typeof params.array !== 'undefined' ? params.array : Array; + const { start, end } = getArrayBounds(rowCount, params); + return { array: new c(end - start) as any[], start, end }; } /** A helped function for Column.toArray */ diff --git a/src/reader/common/text/column/fixed.ts b/src/reader/common/text/column/fixed.ts index ac411242ab8ebde05d71a72e81d8c5e4586a0844..fb7534e85c8736929bbd740e8fb7a0fb76475f8e 100644 --- a/src/reader/common/text/column/fixed.ts +++ b/src/reader/common/text/column/fixed.ts @@ -45,11 +45,9 @@ export function FixedColumn<T extends ColumnType>(lines: Tokens, offset: number, isDefined: true, rowCount, value, - isValueDefined(row) { return true; }, - toArray(params) { return createAndFillArray(rowCount, value, params); }, - stringEquals(row, v) { return value(row) === v; }, - areValuesEqual(rowA, rowB) { - return value(rowA) === value(rowB); - } + isValueDefined: row => true, + toArray: params => createAndFillArray(rowCount, value, params), + stringEquals: (row, v) => value(row) === v, + areValuesEqual: (rowA, rowB) => value(rowA) === value(rowB) }; } \ No newline at end of file diff --git a/src/reader/common/text/column/token.ts b/src/reader/common/text/column/token.ts index 4d30f821118b279df63b88f0fd005bd3d2221837..adfc613d074c1e030fa212ed0fee0c4b61935c74 100644 --- a/src/reader/common/text/column/token.ts +++ b/src/reader/common/text/column/token.ts @@ -33,9 +33,9 @@ export function TokenColumn<T extends ColumnType>(tokens: Tokens, type: T): Colu isDefined: true, rowCount, value, - isValueDefined(row) { return true; }, - toArray(params) { return createAndFillArray(rowCount, value, params); }, - stringEquals(row, v) { + isValueDefined: row => true, + toArray: params => createAndFillArray(rowCount, value, params), + stringEquals: (row, v) => { const s = indices[2 * row]; const value = v || ''; const len = value.length; diff --git a/src/reader/spec/text-column.spec.ts b/src/reader/spec/column.spec.ts similarity index 77% rename from src/reader/spec/text-column.spec.ts rename to src/reader/spec/column.spec.ts index 3d3f15edb39f30b188ad3fa27f2093a734993afd..6e885afd2ee3d6c405725dafc7f822b3eba35350 100644 --- a/src/reader/spec/text-column.spec.ts +++ b/src/reader/spec/column.spec.ts @@ -5,6 +5,7 @@ * @author David Sehnal <david.sehnal@gmail.com> */ +import * as BinaryColumn from '../common/binary/column' import FixedColumn from '../common/text/column/fixed' import TokenColumn from '../common/text/column/token' import { ColumnType } from '../common/column' @@ -60,3 +61,17 @@ describe('token text column', () => { expect(col1.value(2)).toBe(1); }) }); + +describe('binary column', () => { + it('window works', () => { + const xs = new Float64Array([1, 2, 3, 4]); + const w1 = BinaryColumn.typedArrayWindow(xs, { start: 1 }); + const w2 = BinaryColumn.typedArrayWindow(xs, { start: 2, end: 4 }); + + expect(w1.length).toBe(3); + for (let i = 0; i < w1.length; i++) expect(w1[i]).toBe(xs[i + 1]); + + expect(w2.length).toBe(2); + for (let i = 0; i < w2.length; i++) expect(w2[i]).toBe(xs[i + 2]); + }); +})