Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions js/perf/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,12 @@ for (let { name, buffers } of require('./table_config')) {
for (let {name, buffers, countBys, counts} of require('./table_config')) {
const table = Table.from(buffers);

const tableIterateSuiteName = `Table Iterate "${name}"`;
const dfCountBySuiteName = `DataFrame Count By "${name}"`;
const dfFilterCountSuiteName = `DataFrame Filter-Scan Count "${name}"`;
const dfDirectCountSuiteName = `DataFrame Direct Count "${name}"`;

suites.push(createTestSuite(tableIterateSuiteName, createTableIterateTest(table)));
suites.push(...countBys.map((countBy) => createTestSuite(dfCountBySuiteName, createDataFrameCountByTest(table, countBy))));
suites.push(...counts.map(({ col, test, value }) => createTestSuite(dfFilterCountSuiteName, createDataFrameFilterCountTest(table, col, test, value))));
suites.push(...counts.map(({ col, test, value }) => createTestSuite(dfDirectCountSuiteName, createDataFrameDirectCountTest(table, col, test, value))));
Expand Down Expand Up @@ -135,6 +137,15 @@ function createGetByIndexTest(vector, name) {
};
}

function createTableIterateTest(table) {
let value;
return {
async: true,
name: `length: ${table.length}\n`,
fn() { for (value of table) {} }
};
}

function createDataFrameDirectCountTest(table, column, test, value) {
let sum, colidx = table.schema.fields.findIndex((c)=>c.name === column);

Expand Down
19 changes: 17 additions & 2 deletions js/src/util/vector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@ export function createElementComparator(search: any) {
return true;
};
}
// Compare Rows and Vectors
if ((search instanceof Row) || (search instanceof Vector)) {
// Compare Vectors
if (search instanceof Vector) {
const n = search.length;
const C = search.constructor as any;
const fns = [] as ((x: any) => boolean)[];
Expand All @@ -113,6 +113,21 @@ export function createElementComparator(search: any) {
return true;
};
}
// Compare Rows
if (search instanceof Row) {
const n = search.length;
const fns = [] as ((x: any) => boolean)[];
for (let i = -1; ++i < n;) {
fns[i] = createElementComparator((search as any).get(i));
}
return (value: any) => {
if (!(value.length === n)) { return false; }
for (let i = -1; ++i < n;) {
if (!(fns[i](value.get(i)))) { return false; }
}
return true;
};
}
Comment thread
TheNeuralBit marked this conversation as resolved.
// Compare non-empty Objects
const keys = Object.keys(search);
if (keys.length > 0) {
Expand Down
8 changes: 4 additions & 4 deletions js/src/vector/map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.

import { Row } from './row';
import { RowProxyGenerator } from './row';
import { Vector } from '../vector';
import { BaseVector } from './base';
import { DataType, Map_, Struct } from '../type';
Expand All @@ -25,8 +25,8 @@ export class MapVector<T extends { [key: string]: DataType } = any> extends Base
return Vector.new(this.data.clone(new Struct<T>(this.type.children)));
}
// @ts-ignore
private _rowProxy: Row<T>;
public get rowProxy(): Row<T> {
return this._rowProxy || (this._rowProxy = Row.new<T>(this.type.children || [], true));
private _rowProxy: RowProxyGenerator<T>;
public get rowProxy(): RowProxyGenerator<T> {
return this._rowProxy || (this._rowProxy = RowProxyGenerator.new<T>(this.type.children || [], true));
}
}
106 changes: 59 additions & 47 deletions js/src/vector/row.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,56 @@

import { Field } from '../schema';
import { MapVector } from '../vector/map';
import { DataType, RowLike } from '../type';
import { DataType } from '../type';
import { valueToString } from '../util/pretty';
import { StructVector } from '../vector/struct';

/** @ignore */ const columnDescriptor = { enumerable: true, configurable: false, get: () => {} };
/** @ignore */ const lengthDescriptor = { writable: false, enumerable: false, configurable: false, value: -1 };
/** @ignore */ const rowIndexDescriptor = { writable: false, enumerable: false, configurable: true, value: null as any };
/** @ignore */ const rowParentDescriptor = { writable: false, enumerable: false, configurable: false, value: null as any };
/** @ignore */ const row = { parent: rowParentDescriptor, rowIndex: rowIndexDescriptor };

/** @ignore */
export class Row<T extends { [key: string]: DataType }> implements Iterable<T[keyof T]['TValue']> {
[key: string]: T[keyof T]['TValue'];
// @ts-ignore
public parent: MapVector<T> | StructVector<T>;
// @ts-ignore
public rowIndex: number;
// @ts-ignore
public readonly length: number;
constructor(parent: MapVector<T> | StructVector<T>, rowIndex: number) {
this.parent = parent;
this.rowIndex = rowIndex;
}
*[Symbol.iterator]() {
for (let i = -1, n = this.length; ++i < n;) {
yield this[i];
}
}
public get<K extends keyof T>(key: K) { return (this as any)[key] as T[K]['TValue']; }
public toJSON(): any {
return DataType.isStruct(this.parent.type) ? [...this] :
Object.getOwnPropertyNames(this).reduce((props: any, prop: string) => {
return (props[prop] = (this as any)[prop]) && props || props;
}, {});
}
public toString() {
return DataType.isStruct(this.parent.type) ?
[...this].map((x) => valueToString(x)).join(', ') :
Object.getOwnPropertyNames(this).reduce((props: any, prop: string) => {
return (props[prop] = valueToString((this as any)[prop])) && props || props;
}, {});
}
}

interface RowConstructor<T extends { [key: string]: DataType }> {
readonly prototype: Row<T>;
new(parent: MapVector<T> | StructVector<T>, rowIndex: number): T & Row<T>
}


/** @ignore */
export class RowProxyGenerator<T extends { [key: string]: DataType }> {
/** @nocollapse */
public static new<T extends { [key: string]: DataType }>(schemaOrFields: T | Field[], fieldsAreEnumerable = false): RowLike<T> & Row<T> {
public static new<T extends { [key: string]: DataType }>(schemaOrFields: T | Field[], fieldsAreEnumerable = false): RowProxyGenerator<T> {
let schema: T, fields: Field[];
if (Array.isArray(schemaOrFields)) {
fields = schemaOrFields;
Expand All @@ -40,61 +75,38 @@ export class Row<T extends { [key: string]: DataType }> implements Iterable<T[ke
fieldsAreEnumerable = true;
fields = Object.keys(schema).map((x) => new Field(x, schema[x]));
}
return new Row<T>(fields, fieldsAreEnumerable) as RowLike<T> & Row<T>;
return new RowProxyGenerator<T>(fields, fieldsAreEnumerable);
}
// @ts-ignore
private parent: TParent;
// @ts-ignore
private rowIndex: number;
// @ts-ignore
public readonly length: number;

private RowProxy: RowConstructor<T>;

private constructor(fields: Field[], fieldsAreEnumerable: boolean) {
class BoundRow extends Row<T> {}

const proto = BoundRow.prototype;

lengthDescriptor.value = fields.length;
Object.defineProperty(this, 'length', lengthDescriptor);
Object.defineProperty(proto, 'length', lengthDescriptor);
fields.forEach((field, columnIndex) => {
columnDescriptor.get = this._bindGetter(columnIndex);
columnDescriptor.get = function() {
const child = (this as any as Row<T>).parent.getChildAt(columnIndex);
return child ? child.get((this as any as Row<T>).rowIndex) : null;
}
// set configurable to true to ensure Object.defineProperty
// doesn't throw in the case of duplicate column names
columnDescriptor.configurable = true;
columnDescriptor.enumerable = fieldsAreEnumerable;
Object.defineProperty(this, field.name, columnDescriptor);
Object.defineProperty(proto, field.name, columnDescriptor);
columnDescriptor.configurable = false;
columnDescriptor.enumerable = !fieldsAreEnumerable;
Object.defineProperty(this, columnIndex, columnDescriptor);
Object.defineProperty(proto, columnIndex, columnDescriptor);
columnDescriptor.get = null as any;
});
}
*[Symbol.iterator](this: RowLike<T>) {
for (let i = -1, n = this.length; ++i < n;) {
yield this[i];
}
}
private _bindGetter(colIndex: number) {
return function (this: Row<T>) {
let child = this.parent.getChildAt(colIndex);
return child ? child.get(this.rowIndex) : null;
};

this.RowProxy = (BoundRow as any)
}
public get<K extends keyof T>(key: K) { return (this as any)[key] as T[K]['TValue']; }
public bind<TParent extends MapVector<T> | StructVector<T>>(parent: TParent, rowIndex: number) {
rowIndexDescriptor.value = rowIndex;
rowParentDescriptor.value = parent;
const bound = Object.create(this, row);
rowIndexDescriptor.value = null;
rowParentDescriptor.value = null;
return bound as RowLike<T>;
}
public toJSON(): any {
return DataType.isStruct(this.parent.type) ? [...this] :
Object.getOwnPropertyNames(this).reduce((props: any, prop: string) => {
return (props[prop] = (this as any)[prop]) && props || props;
}, {});
}
public toString() {
return DataType.isStruct(this.parent.type) ?
[...this].map((x) => valueToString(x)).join(', ') :
Object.getOwnPropertyNames(this).reduce((props: any, prop: string) => {
return (props[prop] = valueToString((this as any)[prop])) && props || props;
}, {});
return new this.RowProxy(parent, rowIndex);
}
}
8 changes: 4 additions & 4 deletions js/src/vector/struct.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.

import { Row } from './row';
import { RowProxyGenerator } from './row';
import { Vector } from '../vector';
import { BaseVector } from './base';
import { DataType, Map_, Struct } from '../type';
Expand All @@ -25,8 +25,8 @@ export class StructVector<T extends { [key: string]: DataType } = any> extends B
return Vector.new(this.data.clone(new Map_<T>(this.type.children, keysSorted)));
}
// @ts-ignore
private _rowProxy: Row<T>;
public get rowProxy(): Row<T> {
return this._rowProxy || (this._rowProxy = Row.new<T>(this.type.children || [], false));
private _rowProxy: RowProxyGenerator<T>;
public get rowProxy(): RowProxyGenerator<T> {
return this._rowProxy || (this._rowProxy = RowProxyGenerator.new<T>(this.type.children || [], false));
}
}