From 70ae20c1157bff518ba9a22b84799a4129ee9758 Mon Sep 17 00:00:00 2001 From: Dominik Moritz Date: Thu, 21 Mar 2024 10:50:21 -0400 Subject: [PATCH 1/2] GH-39131: [JS] Add at() for array like types --- js/bin/integration.ts | 2 +- js/bin/print-buffer-alignment.ts | 13 +- js/perf/index.ts | 12 +- js/src/builder/buffer.ts | 6 +- js/src/recordbatch.ts | 14 +- js/src/row/map.ts | 10 +- js/src/row/struct.ts | 8 +- js/src/table.ts | 17 +- js/src/util/vector.ts | 4 +- js/src/vector.ts | 33 ++- js/src/visitor/{get.ts => at.ts} | 234 ++++++++++---------- js/src/visitor/indexof.ts | 10 +- js/src/visitor/iterator.ts | 2 +- js/src/visitor/set.ts | 6 +- js/test/inference/column.ts | 8 +- js/test/inference/nested.ts | 4 +- js/test/inference/visitor/{get.ts => at.ts} | 42 ++-- js/test/jest-extensions.ts | 2 +- js/test/unit/bn-tests.ts | 2 +- js/test/unit/builders/utils.ts | 2 +- js/test/unit/generated-data-validators.ts | 8 +- js/test/unit/table-tests.ts | 2 +- js/test/unit/vector/bool-vector-tests.ts | 4 +- js/test/unit/vector/numeric-vector-tests.ts | 2 +- js/test/unit/vector/vector-tests.ts | 6 +- 25 files changed, 242 insertions(+), 211 deletions(-) rename js/src/visitor/{get.ts => at.ts} (52%) rename js/test/inference/visitor/{get.ts => at.ts} (51%) diff --git a/js/bin/integration.ts b/js/bin/integration.ts index f9aad3422ae72..8de9e3517cd20 100755 --- a/js/bin/integration.ts +++ b/js/bin/integration.ts @@ -223,7 +223,7 @@ function compareVectors(actual: Vector, expected: Vector) { (() => { for (let i = -1, n = actual.length; ++i < n;) { - const x1 = actual.get(i), x2 = expected.get(i); + const x1 = actual.at(i), x2 = expected.at(i); if (!createElementComparator(x2)(x1)) { throw new Error(`${i}: ${x1} !== ${x2}`); } diff --git a/js/bin/print-buffer-alignment.ts b/js/bin/print-buffer-alignment.ts index 07563af5a87e8..72bda282cf5c3 100755 --- a/js/bin/print-buffer-alignment.ts +++ b/js/bin/print-buffer-alignment.ts @@ -35,10 +35,9 @@ import { RecordBatch, AsyncMessageReader, makeData, Struct, Schema, Field } from while (1) { // @ts-ignore if ((metadataLength = (await reader.readMetadataLength())).done) { break; } - if (metadataLength.value === -1) { + if (metadataLength.value === -1 && // @ts-ignore - if ((metadataLength = (await reader.readMetadataLength())).done) { break; } - } + (metadataLength = (await reader.readMetadataLength())).done) { break; } // @ts-ignore if ((message = (await reader.readMetadata(metadataLength.value))).done) { break; } @@ -65,9 +64,9 @@ import { RecordBatch, AsyncMessageReader, makeData, Struct, Schema, Field } from bodyByteLength: body.byteLength, }); byteOffset += metadataLength.value; - bufferRegions.forEach(({ offset, length: byteLength }, i) => { + for (const [i, { offset, length: byteLength }] of bufferRegions.entries()) { console.log(`\tbuffer ${i + 1}:`, { byteOffset: byteOffset + offset, byteLength }); - }); + } byteOffset += body.byteLength; } else if (message.value.isDictionaryBatch()) { const header = message.value.header(); @@ -85,9 +84,9 @@ import { RecordBatch, AsyncMessageReader, makeData, Struct, Schema, Field } from bodyByteLength: body.byteLength, }); byteOffset += metadataLength.value; - bufferRegions.forEach(({ offset, length: byteLength }, i) => { + for (const [i, { offset, length: byteLength }] of bufferRegions.entries()) { console.log(`\tbuffer ${i + 1}:`, { byteOffset: byteOffset + offset, byteLength }); - }); + } byteOffset += body.byteLength; } } diff --git a/js/perf/index.ts b/js/perf/index.ts index 2869470b4697f..407606dd8595a 100755 --- a/js/perf/index.ts +++ b/js/perf/index.ts @@ -127,7 +127,7 @@ b.suite( ...Object.entries(vectors).map(([name, vector]) => b.add(`from: ${name}`, () => { for (let i = -1, n = vector.length; ++i < n;) { - vector.get(i); + vector.at(i); } })), @@ -155,7 +155,7 @@ for (const { name, ipc, table } of config) { suite_name: `Get values by index`, fn(vector: Arrow.Vector) { for (let i = -1, n = vector.length; ++i < n;) { - vector.get(i); + vector.at(i); } } }, { @@ -205,9 +205,9 @@ for (const { name, table, counts } of config) { table.toArray(); }), - b.add(`get, dataset: ${name}, numRows: ${formatNumber(table.numRows)}`, () => { + b.add(`at, dataset: ${name}, numRows: ${formatNumber(table.numRows)}`, () => { for (let i = -1, n = table.numRows; ++i < n;) { - table.get(i); + table.at(i); } }), @@ -233,7 +233,7 @@ for (const { name, table, counts } of config) { const vector = batch.getChildAt(colidx)!; // yield all indices for (let index = -1, length = batch.numRows; ++index < length;) { - sum += (vector.get(index) >= value) ? 1 : 0; + sum += (vector.at(index) >= value) ? 1 : 0; } } return sum; @@ -249,7 +249,7 @@ for (const { name, table, counts } of config) { const vector = batch.getChildAt(colidx)!; // yield all indices for (let index = -1, length = batch.numRows; ++index < length;) { - sum += (vector.get(index) === value) ? 1 : 0; + sum += (vector.at(index) === value) ? 1 : 0; } } return sum; diff --git a/js/src/builder/buffer.ts b/js/src/builder/buffer.ts index ad1c06b0d9f0f..008683e81c424 100644 --- a/js/src/builder/buffer.ts +++ b/js/src/builder/buffer.ts @@ -91,8 +91,8 @@ export class BufferBuilder { /** @ignore */ export class DataBufferBuilder extends BufferBuilder { - public last() { return this.get(this.length - 1); } - public get(index: number): T[0] { return this.buffer[index]; } + public last() { return this.at(- 1); } + public at(index: number): T[0] { return this.buffer[index]; } public set(index: number, value: T[0]) { this.reserve(index - this.length + 1); this.buffer[index * this.stride] = value; @@ -107,7 +107,7 @@ export class BitmapBufferBuilder extends DataBufferBuilder { public numValid = 0; public get numInvalid() { return this.length - this.numValid; } - public get(idx: number) { return this.buffer[idx >> 3] >> idx % 8 & 1; } + public at(idx: number) { return this.buffer[idx >> 3] >> idx % 8 & 1; } public set(idx: number, val: number) { const { buffer } = this.reserve(idx - this.length + 1); const byte = idx >> 3, bit = idx % 8, cur = buffer[byte] >> bit & 1; diff --git a/js/src/recordbatch.ts b/js/src/recordbatch.ts index b9061c8b9bb04..8ccd6b22ce7ee 100644 --- a/js/src/recordbatch.ts +++ b/js/src/recordbatch.ts @@ -21,7 +21,7 @@ import { Vector } from './vector.js'; import { Schema, Field } from './schema.js'; import { DataType, Struct, Null, TypeMap } from './type.js'; -import { instance as getVisitor } from './visitor/get.js'; +import { instance as atVisitor } from './visitor/at.js'; import { instance as setVisitor } from './visitor/set.js'; import { instance as indexOfVisitor } from './visitor/indexof.js'; import { instance as iteratorVisitor } from './visitor/iterator.js'; @@ -124,11 +124,21 @@ export class RecordBatch { } /** + * @deprecated Use `at()` instead. + * * Get a row by position. * @param index The index of the element to read. */ public get(index: number) { - return getVisitor.visit(this.data, index); + return this.at(index); + } + + /** + * Get an element value by position. + * @param index The index of the element to read. A negative index will count back from the last element. + */ + public at(index: number) { + return atVisitor.visit(this.data, index); } /** diff --git a/js/src/row/map.ts b/js/src/row/map.ts index d0ccb872ec33c..4f8a3bb4257e6 100644 --- a/js/src/row/map.ts +++ b/js/src/row/map.ts @@ -19,7 +19,7 @@ import { Data } from '../data.js'; import { Vector } from '../vector.js'; import { DataType, Struct } from '../type.js'; import { valueToString } from '../util/pretty.js'; -import { instance as getVisitor } from '../visitor/get.js'; +import { instance as atVisitor } from '../visitor/at.js'; import { instance as setVisitor } from '../visitor/set.js'; /** @ignore */ export const kKeys = Symbol.for('keys'); @@ -51,7 +51,7 @@ export class MapRow { const vals = this[kVals]; const json = {} as { [P in K['TValue']]: V['TValue'] }; for (let i = -1, n = keys.length; ++i < n;) { - json[keys.get(i)] = getVisitor.visit(vals, i); + json[keys.at(i)] = atVisitor.visit(vals, i); } return json; } @@ -94,8 +94,8 @@ class MapRowIterator return { done: false, value: [ - this.keys.get(i), - getVisitor.visit(this.vals, i), + this.keys.at(i), + atVisitor.visit(this.vals, i), ] as [K['TValue'], V['TValue'] | null] }; } @@ -126,7 +126,7 @@ class MapRowProxyHandler imp } const idx = row[kKeys].indexOf(key); if (idx !== -1) { - const val = getVisitor.visit(Reflect.get(row, kVals), idx); + const val = atVisitor.visit(Reflect.get(row, kVals), idx); // Cache key/val lookups Reflect.set(row, key, val); return val; diff --git a/js/src/row/struct.ts b/js/src/row/struct.ts index 094f6a4b11ac8..c2b92cadac445 100644 --- a/js/src/row/struct.ts +++ b/js/src/row/struct.ts @@ -19,7 +19,7 @@ import { Data } from '../data.js'; import { Field } from '../schema.js'; import { Struct, TypeMap } from '../type.js'; import { valueToString } from '../util/pretty.js'; -import { instance as getVisitor } from '../visitor/get.js'; +import { instance as atVisitor } from '../visitor/at.js'; import { instance as setVisitor } from '../visitor/set.js'; /** @ignore */ const kParent = Symbol.for('parent'); @@ -50,7 +50,7 @@ export class StructRow { const keys = parent.type.children; const json = {} as { [P in string & keyof T]: T[P]['TValue'] }; for (let j = -1, n = keys.length; ++j < n;) { - json[keys[j].name as string & keyof T] = getVisitor.visit(parent.children[j], i); + json[keys[j].name as string & keyof T] = atVisitor.visit(parent.children[j], i); } return json; } @@ -102,7 +102,7 @@ class StructRowIterator done: false, value: [ this.childFields[i].name, - getVisitor.visit(this.children[i], this.rowIndex) + atVisitor.visit(this.children[i], this.rowIndex) ] } as IteratorYieldResult<[any, any]>; } @@ -139,7 +139,7 @@ class StructRowProxyHandler implements ProxyHandler f.name === key); if (idx !== -1) { - const val = getVisitor.visit(row[kParent].children[idx], row[kRowIndex]); + const val = atVisitor.visit(row[kParent].children[idx], row[kRowIndex]); // Cache key/val lookups Reflect.set(row, key, val); return val; diff --git a/js/src/table.ts b/js/src/table.ts index d7a6617530a8e..0e483710320cc 100644 --- a/js/src/table.ts +++ b/js/src/table.ts @@ -34,7 +34,7 @@ import { sliceChunks, } from './util/chunk.js'; -import { instance as getVisitor } from './visitor/get.js'; +import { instance as atVisitor } from './visitor/at.js'; import { instance as setVisitor } from './visitor/set.js'; import { instance as indexOfVisitor } from './visitor/indexof.js'; import { instance as iteratorVisitor } from './visitor/iterator.js'; @@ -189,12 +189,23 @@ export class Table { public isValid(index: number): boolean { return false; } /** + * @deprecated Use `at()` instead. + * * Get an element value by position. * * @param index The index of the element to read. */ // @ts-ignore - public get(index: number): Struct['TValue'] | null { return null; } + public get(index: number): Struct['TValue'] | null { + return this.at(index); + } + + /** + * Get an element value by position. + * @param index The index of the element to read. A negative index will count back from the last element. + */ + // @ts-ignore + public at(index: number): Struct['TValue'] | null { return null; } /** * Set an element value by position. @@ -379,7 +390,7 @@ export class Table { (proto as any)._nullCount = -1; (proto as any)[Symbol.isConcatSpreadable] = true; (proto as any)['isValid'] = wrapChunkedCall1(isChunkedValid); - (proto as any)['get'] = wrapChunkedCall1(getVisitor.getVisitFn(Type.Struct)); + (proto as any)['at'] = wrapChunkedCall1(atVisitor.getVisitFn(Type.Struct)); (proto as any)['set'] = wrapChunkedCall2(setVisitor.getVisitFn(Type.Struct)); (proto as any)['indexOf'] = wrapChunkedIndexOf(indexOfVisitor.getVisitFn(Type.Struct)); return 'Table'; diff --git a/js/src/util/vector.ts b/js/src/util/vector.ts index 179b17a39f3f3..938cd648ae488 100644 --- a/js/src/util/vector.ts +++ b/js/src/util/vector.ts @@ -114,7 +114,7 @@ function createMapComparator(lhs: Map) { function createVectorComparator(lhs: Vector) { const comparators = [] as ((x: any) => boolean)[]; for (let i = -1, n = lhs.length; ++i < n;) { - comparators[i] = createElementComparator(lhs.get(i)); + comparators[i] = createElementComparator(lhs.at(i)); } return createSubElementsComparator(comparators); } @@ -163,7 +163,7 @@ function compareVector(comparators: ((x: any) => boolean)[], vec: Vector) { const n = comparators.length; if (vec.length !== n) { return false; } for (let i = -1; ++i < n;) { - if (!(comparators[i](vec.get(i)))) { return false; } + if (!(comparators[i](vec.at(i)))) { return false; } } return true; } diff --git a/js/src/vector.ts b/js/src/vector.ts index a7c103bc326ee..5a0bdb1742ddd 100644 --- a/js/src/vector.ts +++ b/js/src/vector.ts @@ -32,7 +32,7 @@ import { wrapChunkedIndexOf, } from './util/chunk.js'; -import { instance as getVisitor } from './visitor/get.js'; +import { instance as atVisitor } from './visitor/at.js'; import { instance as setVisitor } from './visitor/set.js'; import { instance as indexOfVisitor } from './visitor/indexof.js'; import { instance as iteratorVisitor } from './visitor/iterator.js'; @@ -55,7 +55,7 @@ export interface Vector { [Symbol.isConcatSpreadable]: true; } -const visitorsByTypeId = {} as { [typeId: number]: { get: any; set: any; indexOf: any } }; +const visitorsByTypeId = {} as { [typeId: number]: { at: any; set: any; indexOf: any } }; const vectorPrototypesByTypeId = {} as { [typeId: number]: any }; /** @@ -75,11 +75,11 @@ export class Vector { case 0: this._offsets = [0]; break; case 1: { // special case for unchunked vectors - const { get, set, indexOf } = visitorsByTypeId[type.typeId]; + const { at, set, indexOf } = visitorsByTypeId[type.typeId]; const unchunkedData = data[0]; this.isValid = (index: number) => isChunkedValid(unchunkedData, index); - this.get = (index: number) => get(unchunkedData, index); + this.at = (index: number) => at(unchunkedData, index); this.set = (index: number, value: T) => set(unchunkedData, index, value); this.indexOf = (index: number) => indexOf(unchunkedData, index); this._offsets = [0, unchunkedData.length]; @@ -171,11 +171,22 @@ export class Vector { public isValid(index: number): boolean { return false; } /** + * @deprecated Use `at()` instead. + * * Get an element value by position. * @param index The index of the element to read. */ // @ts-ignore - public get(index: number): T['TValue'] | null { return null; } + public get(index: number): T['TValue'] | null { + return this.at(index) ?? null; + } + + /** + * Get an element value by position. + * @param index The index of the element to read. A negative index will count back from the last element. + */ + // @ts-ignore + public at(index: number): T['TValue'] | null { return null; } /** * Set an element value by position. @@ -354,14 +365,14 @@ export class Vector { .filter((T: any) => typeof T === 'number' && T !== Type.NONE); for (const typeId of typeIds) { - const get = getVisitor.getVisitFnByTypeId(typeId); + const at = atVisitor.getVisitFnByTypeId(typeId); const set = setVisitor.getVisitFnByTypeId(typeId); const indexOf = indexOfVisitor.getVisitFnByTypeId(typeId); - visitorsByTypeId[typeId] = { get, set, indexOf }; + visitorsByTypeId[typeId] = { at, set, indexOf }; vectorPrototypesByTypeId[typeId] = Object.create(proto, { ['isValid']: { value: wrapChunkedCall1(isChunkedValid) }, - ['get']: { value: wrapChunkedCall1(getVisitor.getVisitFnByTypeId(typeId)) }, + ['at']: { value: wrapChunkedCall1(atVisitor.getVisitFnByTypeId(typeId)) }, ['set']: { value: wrapChunkedCall2(setVisitor.getVisitFnByTypeId(typeId)) }, ['indexOf']: { value: wrapChunkedIndexOf(indexOfVisitor.getVisitFnByTypeId(typeId)) }, }); @@ -376,19 +387,19 @@ class MemoizedVector extends Vector { public constructor(vector: Vector) { super(vector.data); - const get = this.get; + const at = this.at; const set = this.set; const slice = this.slice; const cache = new Array(this.length); - Object.defineProperty(this, 'get', { + Object.defineProperty(this, 'at', { value(index: number) { const cachedValue = cache[index]; if (cachedValue !== undefined) { return cachedValue; } - const value = get.call(this, index); + const value = at.call(this, index); cache[index] = value; return value; } diff --git a/js/src/visitor/get.ts b/js/src/visitor/at.ts similarity index 52% rename from js/src/visitor/get.ts rename to js/src/visitor/at.ts index 3ab3bcb68c386..f4e36cf5740c2 100644 --- a/js/src/visitor/get.ts +++ b/js/src/visitor/at.ts @@ -40,11 +40,11 @@ import { } from '../type.js'; /** @ignore */ -export interface GetVisitor extends Visitor { +export interface AtVisitor extends Visitor { visit(node: Data, index: number): T['TValue'] | null; visitMany(nodes: Data[], indices: number[]): (T['TValue'] | null)[]; - getVisitFn(node: Vector | Data | T): (data: Data, index: number) => T['TValue'] | null; - getVisitFn(node: T): (data: Data>, index: number) => TypeToDataType['TValue']; + atVisitFn(node: Vector | Data | T): (data: Data, index: number) => T['TValue'] | null; + atVisitFn(node: T): (data: Data>, index: number) => TypeToDataType['TValue']; visitNull(data: Data, index: number): T['TValue'] | null; visitBool(data: Data, index: number): T['TValue'] | null; visitInt(data: Data, index: number): T['TValue'] | null; @@ -98,10 +98,10 @@ export interface GetVisitor extends Visitor { } /** @ignore */ -export class GetVisitor extends Visitor { } +export class AtVisitor extends Visitor { } /** @ignore */ -function wrapGet(fn: (data: Data, _1: any) => any) { +function wrapAt(fn: (data: Data, _1: any) => any) { return (data: Data, _1: any) => data.getValid(_1) ? fn(data, _1) : null; } @@ -115,9 +115,9 @@ function wrapGet(fn: (data: Data, _1: any) => any) { /** @ignore */const epochMillisecondsLongToDate = (data: Int32Array, index: number) => epochMillisecondsToDate(epochMillisecondsLongToMs(data, index)); /** @ignore */ -const getNull = (_data: Data, _index: number): T['TValue'] => null; +const atNull = (_data: Data, _index: number): T['TValue'] => null; /** @ignore */ -const getVariableWidthBytes = (values: Uint8Array, valueOffsets: Int32Array | BigInt64Array, index: number) => { +const atVariableWidthBytes = (values: Uint8Array, valueOffsets: Int32Array | BigInt64Array, index: number) => { if (index + 1 >= valueOffsets.length) { return null as any; } @@ -127,7 +127,7 @@ const getVariableWidthBytes = (values: Uint8Array, valueOffsets: Int32Array | Bi }; /** @ignore */ -const getBool = ({ offset, values }: Data, index: number): T['TValue'] => { +const atBool = ({ offset, values }: Data, index: number): T['TValue'] => { const idx = offset + index; const byte = values[idx >> 3]; return (byte & 1 << (idx % 8)) !== 0; @@ -139,87 +139,87 @@ type Numeric1X = Int8 | Int16 | Int32 | Uint8 | Uint16 | Uint32 | Float32 | Floa type Numeric2X = Int64 | Uint64; /** @ignore */ -const getDateDay = ({ values }: Data, index: number): T['TValue'] => epochDaysToDate(values, index); +const atDateDay = ({ values }: Data, index: number): T['TValue'] => epochDaysToDate(values, index); /** @ignore */ -const getDateMillisecond = ({ values }: Data, index: number): T['TValue'] => epochMillisecondsLongToDate(values, index * 2); +const atDateMillisecond = ({ values }: Data, index: number): T['TValue'] => epochMillisecondsLongToDate(values, index * 2); /** @ignore */ -const getNumeric = ({ stride, values }: Data, index: number): T['TValue'] => values[stride * index]; +const atNumeric = ({ stride, values }: Data, index: number): T['TValue'] => values[stride * index]; /** @ignore */ -const getFloat16 = ({ stride, values }: Data, index: number): T['TValue'] => uint16ToFloat64(values[stride * index]); +const atFloat16 = ({ stride, values }: Data, index: number): T['TValue'] => uint16ToFloat64(values[stride * index]); /** @ignore */ -const getBigInts = ({ values }: Data, index: number): T['TValue'] => values[index]; +const atBigInts = ({ values }: Data, index: number): T['TValue'] => values[index]; /** @ignore */ -const getFixedSizeBinary = ({ stride, values }: Data, index: number): T['TValue'] => values.subarray(stride * index, stride * (index + 1)); +const atFixedSizeBinary = ({ stride, values }: Data, index: number): T['TValue'] => values.subarray(stride * index, stride * (index + 1)); /** @ignore */ -const getBinary = ({ values, valueOffsets }: Data, index: number): T['TValue'] => getVariableWidthBytes(values, valueOffsets, index); +const atBinary = ({ values, valueOffsets }: Data, index: number): T['TValue'] => atVariableWidthBytes(values, valueOffsets, index); /** @ignore */ -const getUtf8 = ({ values, valueOffsets }: Data, index: number): T['TValue'] => { - const bytes = getVariableWidthBytes(values, valueOffsets, index); +const atUtf8 = ({ values, valueOffsets }: Data, index: number): T['TValue'] => { + const bytes = atVariableWidthBytes(values, valueOffsets, index); return bytes !== null ? decodeUtf8(bytes) : null as any; }; /* istanbul ignore next */ /** @ignore */ -const getInt = ({ values }: Data, index: number): T['TValue'] => values[index]; +const atInt = ({ values }: Data, index: number): T['TValue'] => values[index]; /* istanbul ignore next */ /** @ignore */ -const getFloat = ({ type, values }: Data, index: number): T['TValue'] => ( +const atFloat = ({ type, values }: Data, index: number): T['TValue'] => ( type.precision !== Precision.HALF ? values[index] : uint16ToFloat64(values[index]) ); /* istanbul ignore next */ /** @ignore */ -const getDate = (data: Data, index: number): T['TValue'] => ( +const atDate = (data: Data, index: number): T['TValue'] => ( data.type.unit === DateUnit.DAY - ? getDateDay(data as Data, index) - : getDateMillisecond(data as Data, index) + ? atDateDay(data as Data, index) + : atDateMillisecond(data as Data, index) ); /** @ignore */ -const getTimestampSecond = ({ values }: Data, index: number): T['TValue'] => 1000 * epochMillisecondsLongToMs(values, index * 2); +const atTimestampSecond = ({ values }: Data, index: number): T['TValue'] => 1000 * epochMillisecondsLongToMs(values, index * 2); /** @ignore */ -const getTimestampMillisecond = ({ values }: Data, index: number): T['TValue'] => epochMillisecondsLongToMs(values, index * 2); +const atTimestampMillisecond = ({ values }: Data, index: number): T['TValue'] => epochMillisecondsLongToMs(values, index * 2); /** @ignore */ -const getTimestampMicrosecond = ({ values }: Data, index: number): T['TValue'] => epochMicrosecondsLongToMs(values, index * 2); +const atTimestampMicrosecond = ({ values }: Data, index: number): T['TValue'] => epochMicrosecondsLongToMs(values, index * 2); /** @ignore */ -const getTimestampNanosecond = ({ values }: Data, index: number): T['TValue'] => epochNanosecondsLongToMs(values, index * 2); +const atTimestampNanosecond = ({ values }: Data, index: number): T['TValue'] => epochNanosecondsLongToMs(values, index * 2); /* istanbul ignore next */ /** @ignore */ -const getTimestamp = (data: Data, index: number): T['TValue'] => { +const atTimestamp = (data: Data, index: number): T['TValue'] => { switch (data.type.unit) { - case TimeUnit.SECOND: return getTimestampSecond(data as Data, index); - case TimeUnit.MILLISECOND: return getTimestampMillisecond(data as Data, index); - case TimeUnit.MICROSECOND: return getTimestampMicrosecond(data as Data, index); - case TimeUnit.NANOSECOND: return getTimestampNanosecond(data as Data, index); + case TimeUnit.SECOND: return atTimestampSecond(data as Data, index); + case TimeUnit.MILLISECOND: return atTimestampMillisecond(data as Data, index); + case TimeUnit.MICROSECOND: return atTimestampMicrosecond(data as Data, index); + case TimeUnit.NANOSECOND: return atTimestampNanosecond(data as Data, index); } }; /** @ignore */ -const getTimeSecond = ({ values }: Data, index: number): T['TValue'] => values[index]; +const atTimeSecond = ({ values }: Data, index: number): T['TValue'] => values[index]; /** @ignore */ -const getTimeMillisecond = ({ values }: Data, index: number): T['TValue'] => values[index]; +const atTimeMillisecond = ({ values }: Data, index: number): T['TValue'] => values[index]; /** @ignore */ -const getTimeMicrosecond = ({ values }: Data, index: number): T['TValue'] => values[index]; +const atTimeMicrosecond = ({ values }: Data, index: number): T['TValue'] => values[index]; /** @ignore */ -const getTimeNanosecond = ({ values }: Data, index: number): T['TValue'] => values[index]; +const atTimeNanosecond = ({ values }: Data, index: number): T['TValue'] => values[index]; /* istanbul ignore next */ /** @ignore */ -const getTime = (data: Data, index: number): T['TValue'] => { +const atTime = (data: Data, index: number): T['TValue'] => { switch (data.type.unit) { - case TimeUnit.SECOND: return getTimeSecond(data as Data, index); - case TimeUnit.MILLISECOND: return getTimeMillisecond(data as Data, index); - case TimeUnit.MICROSECOND: return getTimeMicrosecond(data as Data, index); - case TimeUnit.NANOSECOND: return getTimeNanosecond(data as Data, index); + case TimeUnit.SECOND: return atTimeSecond(data as Data, index); + case TimeUnit.MILLISECOND: return atTimeMillisecond(data as Data, index); + case TimeUnit.MICROSECOND: return atTimeMicrosecond(data as Data, index); + case TimeUnit.NANOSECOND: return atTimeNanosecond(data as Data, index); } }; /** @ignore */ -const getDecimal = ({ values, stride }: Data, index: number): T['TValue'] => BN.decimal(values.subarray(stride * index, stride * (index + 1))); +const atDecimal = ({ values, stride }: Data, index: number): T['TValue'] => BN.decimal(values.subarray(stride * index, stride * (index + 1))); /** @ignore */ -const getList = (data: Data, index: number): T['TValue'] => { +const atList = (data: Data, index: number): T['TValue'] => { const { valueOffsets, stride, children } = data; const { [index * stride]: begin, [index * stride + 1]: end } = valueOffsets; const child: Data = children[0]; @@ -228,7 +228,7 @@ const getList = (data: Data, index: number): T['TValue'] => { }; /** @ignore */ -const getMap = (data: Data, index: number): T['TValue'] => { +const atMap = (data: Data, index: number): T['TValue'] => { const { valueOffsets, children } = data; const { [index]: begin, [index + 1]: end } = valueOffsets; const child = children[0] as Data; @@ -236,51 +236,51 @@ const getMap = (data: Data, index: number): T['TValue'] => { }; /** @ignore */ -const getStruct = (data: Data, index: number): T['TValue'] => { +const atStruct = (data: Data, index: number): T['TValue'] => { return new StructRow(data, index) as StructRowProxy; }; /* istanbul ignore next */ /** @ignore */ -const getUnion = < +const atUnion = < D extends Data | Data | Data >(data: D, index: number): D['TValue'] => { return data.type.mode === UnionMode.Dense ? - getDenseUnion(data as Data, index) : - getSparseUnion(data as Data, index); + atDenseUnion(data as Data, index) : + atSparseUnion(data as Data, index); }; /** @ignore */ -const getDenseUnion = (data: Data, index: number): T['TValue'] => { +const atDenseUnion = (data: Data, index: number): T['TValue'] => { const childIndex = data.type.typeIdToChildIndex[data.typeIds[index]]; const child = data.children[childIndex]; return instance.visit(child, data.valueOffsets[index]); }; /** @ignore */ -const getSparseUnion = (data: Data, index: number): T['TValue'] => { +const atSparseUnion = (data: Data, index: number): T['TValue'] => { const childIndex = data.type.typeIdToChildIndex[data.typeIds[index]]; const child = data.children[childIndex]; return instance.visit(child, index); }; /** @ignore */ -const getDictionary = (data: Data, index: number): T['TValue'] => { - return data.dictionary?.get(data.values[index]); +const atDictionary = (data: Data, index: number): T['TValue'] => { + return data.dictionary?.at(data.values[index]); }; /* istanbul ignore next */ /** @ignore */ -const getInterval = (data: Data, index: number): T['TValue'] => +const atInterval = (data: Data, index: number): T['TValue'] => (data.type.unit === IntervalUnit.DAY_TIME) - ? getIntervalDayTime(data as Data, index) - : getIntervalYearMonth(data as Data, index); + ? atIntervalDayTime(data as Data, index) + : atIntervalYearMonth(data as Data, index); /** @ignore */ -const getIntervalDayTime = ({ values }: Data, index: number): T['TValue'] => values.subarray(2 * index, 2 * (index + 1)); +const atIntervalDayTime = ({ values }: Data, index: number): T['TValue'] => values.subarray(2 * index, 2 * (index + 1)); /** @ignore */ -const getIntervalYearMonth = ({ values }: Data, index: number): T['TValue'] => { +const atIntervalYearMonth = ({ values }: Data, index: number): T['TValue'] => { const interval = values[index]; const int32s = new Int32Array(2); int32s[0] = Math.trunc(interval / 12); /* years */ @@ -289,82 +289,82 @@ const getIntervalYearMonth = ({ values }: Data, }; /** @ignore */ -const getDurationSecond = ({ values }: Data, index: number): T['TValue'] => values[index]; +const atDurationSecond = ({ values }: Data, index: number): T['TValue'] => values[index]; /** @ignore */ -const getDurationMillisecond = ({ values }: Data, index: number): T['TValue'] => values[index]; +const atDurationMillisecond = ({ values }: Data, index: number): T['TValue'] => values[index]; /** @ignore */ -const getDurationMicrosecond = ({ values }: Data, index: number): T['TValue'] => values[index]; +const atDurationMicrosecond = ({ values }: Data, index: number): T['TValue'] => values[index]; /** @ignore */ -const getDurationNanosecond = ({ values }: Data, index: number): T['TValue'] => values[index]; +const atDurationNanosecond = ({ values }: Data, index: number): T['TValue'] => values[index]; /* istanbul ignore next */ /** @ignore */ -const getDuration = (data: Data, index: number): T['TValue'] => { +const atDuration = (data: Data, index: number): T['TValue'] => { switch (data.type.unit) { - case TimeUnit.SECOND: return getDurationSecond(data as Data, index); - case TimeUnit.MILLISECOND: return getDurationMillisecond(data as Data, index); - case TimeUnit.MICROSECOND: return getDurationMicrosecond(data as Data, index); - case TimeUnit.NANOSECOND: return getDurationNanosecond(data as Data, index); + case TimeUnit.SECOND: return atDurationSecond(data as Data, index); + case TimeUnit.MILLISECOND: return atDurationMillisecond(data as Data, index); + case TimeUnit.MICROSECOND: return atDurationMicrosecond(data as Data, index); + case TimeUnit.NANOSECOND: return atDurationNanosecond(data as Data, index); } }; /** @ignore */ -const getFixedSizeList = (data: Data, index: number): T['TValue'] => { +const atFixedSizeList = (data: Data, index: number): T['TValue'] => { const { stride, children } = data; const child: Data = children[0]; const slice = child.slice(index * stride, stride); return new Vector([slice]); }; -GetVisitor.prototype.visitNull = wrapGet(getNull); -GetVisitor.prototype.visitBool = wrapGet(getBool); -GetVisitor.prototype.visitInt = wrapGet(getInt); -GetVisitor.prototype.visitInt8 = wrapGet(getNumeric); -GetVisitor.prototype.visitInt16 = wrapGet(getNumeric); -GetVisitor.prototype.visitInt32 = wrapGet(getNumeric); -GetVisitor.prototype.visitInt64 = wrapGet(getBigInts); -GetVisitor.prototype.visitUint8 = wrapGet(getNumeric); -GetVisitor.prototype.visitUint16 = wrapGet(getNumeric); -GetVisitor.prototype.visitUint32 = wrapGet(getNumeric); -GetVisitor.prototype.visitUint64 = wrapGet(getBigInts); -GetVisitor.prototype.visitFloat = wrapGet(getFloat); -GetVisitor.prototype.visitFloat16 = wrapGet(getFloat16); -GetVisitor.prototype.visitFloat32 = wrapGet(getNumeric); -GetVisitor.prototype.visitFloat64 = wrapGet(getNumeric); -GetVisitor.prototype.visitUtf8 = wrapGet(getUtf8); -GetVisitor.prototype.visitLargeUtf8 = wrapGet(getUtf8); -GetVisitor.prototype.visitBinary = wrapGet(getBinary); -GetVisitor.prototype.visitLargeBinary = wrapGet(getBinary); -GetVisitor.prototype.visitFixedSizeBinary = wrapGet(getFixedSizeBinary); -GetVisitor.prototype.visitDate = wrapGet(getDate); -GetVisitor.prototype.visitDateDay = wrapGet(getDateDay); -GetVisitor.prototype.visitDateMillisecond = wrapGet(getDateMillisecond); -GetVisitor.prototype.visitTimestamp = wrapGet(getTimestamp); -GetVisitor.prototype.visitTimestampSecond = wrapGet(getTimestampSecond); -GetVisitor.prototype.visitTimestampMillisecond = wrapGet(getTimestampMillisecond); -GetVisitor.prototype.visitTimestampMicrosecond = wrapGet(getTimestampMicrosecond); -GetVisitor.prototype.visitTimestampNanosecond = wrapGet(getTimestampNanosecond); -GetVisitor.prototype.visitTime = wrapGet(getTime); -GetVisitor.prototype.visitTimeSecond = wrapGet(getTimeSecond); -GetVisitor.prototype.visitTimeMillisecond = wrapGet(getTimeMillisecond); -GetVisitor.prototype.visitTimeMicrosecond = wrapGet(getTimeMicrosecond); -GetVisitor.prototype.visitTimeNanosecond = wrapGet(getTimeNanosecond); -GetVisitor.prototype.visitDecimal = wrapGet(getDecimal); -GetVisitor.prototype.visitList = wrapGet(getList); -GetVisitor.prototype.visitStruct = wrapGet(getStruct); -GetVisitor.prototype.visitUnion = wrapGet(getUnion); -GetVisitor.prototype.visitDenseUnion = wrapGet(getDenseUnion); -GetVisitor.prototype.visitSparseUnion = wrapGet(getSparseUnion); -GetVisitor.prototype.visitDictionary = wrapGet(getDictionary); -GetVisitor.prototype.visitInterval = wrapGet(getInterval); -GetVisitor.prototype.visitIntervalDayTime = wrapGet(getIntervalDayTime); -GetVisitor.prototype.visitIntervalYearMonth = wrapGet(getIntervalYearMonth); -GetVisitor.prototype.visitDuration = wrapGet(getDuration); -GetVisitor.prototype.visitDurationSecond = wrapGet(getDurationSecond); -GetVisitor.prototype.visitDurationMillisecond = wrapGet(getDurationMillisecond); -GetVisitor.prototype.visitDurationMicrosecond = wrapGet(getDurationMicrosecond); -GetVisitor.prototype.visitDurationNanosecond = wrapGet(getDurationNanosecond); -GetVisitor.prototype.visitFixedSizeList = wrapGet(getFixedSizeList); -GetVisitor.prototype.visitMap = wrapGet(getMap); +AtVisitor.prototype.visitNull = wrapAt(atNull); +AtVisitor.prototype.visitBool = wrapAt(atBool); +AtVisitor.prototype.visitInt = wrapAt(atInt); +AtVisitor.prototype.visitInt8 = wrapAt(atNumeric); +AtVisitor.prototype.visitInt16 = wrapAt(atNumeric); +AtVisitor.prototype.visitInt32 = wrapAt(atNumeric); +AtVisitor.prototype.visitInt64 = wrapAt(atBigInts); +AtVisitor.prototype.visitUint8 = wrapAt(atNumeric); +AtVisitor.prototype.visitUint16 = wrapAt(atNumeric); +AtVisitor.prototype.visitUint32 = wrapAt(atNumeric); +AtVisitor.prototype.visitUint64 = wrapAt(atBigInts); +AtVisitor.prototype.visitFloat = wrapAt(atFloat); +AtVisitor.prototype.visitFloat16 = wrapAt(atFloat16); +AtVisitor.prototype.visitFloat32 = wrapAt(atNumeric); +AtVisitor.prototype.visitFloat64 = wrapAt(atNumeric); +AtVisitor.prototype.visitUtf8 = wrapAt(atUtf8); +AtVisitor.prototype.visitLargeUtf8 = wrapAt(atUtf8); +AtVisitor.prototype.visitBinary = wrapAt(atBinary); +AtVisitor.prototype.visitLargeBinary = wrapAt(atBinary); +AtVisitor.prototype.visitFixedSizeBinary = wrapAt(atFixedSizeBinary); +AtVisitor.prototype.visitDate = wrapAt(atDate); +AtVisitor.prototype.visitDateDay = wrapAt(atDateDay); +AtVisitor.prototype.visitDateMillisecond = wrapAt(atDateMillisecond); +AtVisitor.prototype.visitTimestamp = wrapAt(atTimestamp); +AtVisitor.prototype.visitTimestampSecond = wrapAt(atTimestampSecond); +AtVisitor.prototype.visitTimestampMillisecond = wrapAt(atTimestampMillisecond); +AtVisitor.prototype.visitTimestampMicrosecond = wrapAt(atTimestampMicrosecond); +AtVisitor.prototype.visitTimestampNanosecond = wrapAt(atTimestampNanosecond); +AtVisitor.prototype.visitTime = wrapAt(atTime); +AtVisitor.prototype.visitTimeSecond = wrapAt(atTimeSecond); +AtVisitor.prototype.visitTimeMillisecond = wrapAt(atTimeMillisecond); +AtVisitor.prototype.visitTimeMicrosecond = wrapAt(atTimeMicrosecond); +AtVisitor.prototype.visitTimeNanosecond = wrapAt(atTimeNanosecond); +AtVisitor.prototype.visitDecimal = wrapAt(atDecimal); +AtVisitor.prototype.visitList = wrapAt(atList); +AtVisitor.prototype.visitStruct = wrapAt(atStruct); +AtVisitor.prototype.visitUnion = wrapAt(atUnion); +AtVisitor.prototype.visitDenseUnion = wrapAt(atDenseUnion); +AtVisitor.prototype.visitSparseUnion = wrapAt(atSparseUnion); +AtVisitor.prototype.visitDictionary = wrapAt(atDictionary); +AtVisitor.prototype.visitInterval = wrapAt(atInterval); +AtVisitor.prototype.visitIntervalDayTime = wrapAt(atIntervalDayTime); +AtVisitor.prototype.visitIntervalYearMonth = wrapAt(atIntervalYearMonth); +AtVisitor.prototype.visitDuration = wrapAt(atDuration); +AtVisitor.prototype.visitDurationSecond = wrapAt(atDurationSecond); +AtVisitor.prototype.visitDurationMillisecond = wrapAt(atDurationMillisecond); +AtVisitor.prototype.visitDurationMicrosecond = wrapAt(atDurationMicrosecond); +AtVisitor.prototype.visitDurationNanosecond = wrapAt(atDurationNanosecond); +AtVisitor.prototype.visitFixedSizeList = wrapAt(atFixedSizeList); +AtVisitor.prototype.visitMap = wrapAt(atMap); /** @ignore */ -export const instance = new GetVisitor(); +export const instance = new AtVisitor(); diff --git a/js/src/visitor/indexof.ts b/js/src/visitor/indexof.ts index 1e1cb87a9840e..2792548069f37 100644 --- a/js/src/visitor/indexof.ts +++ b/js/src/visitor/indexof.ts @@ -18,7 +18,7 @@ import { Data } from '../data.js'; import { Type } from '../enum.js'; import { Visitor } from '../visitor.js'; -import { instance as getVisitor } from './get.js'; +import { instance as atVisitor } from './at.js'; import { TypeToDataType } from '../interfaces.js'; import { getBool, BitIterator } from '../util/bit.js'; import { createElementComparator } from '../util/vector.js'; @@ -132,10 +132,10 @@ function indexOfValue(data: Data, searchElement?: T['TVal return indexOfNull(data, fromIndex); } } - const get = getVisitor.getVisitFn(data); + const at = atVisitor.getVisitFn(data); const compare = createElementComparator(searchElement); for (let i = (fromIndex || 0) - 1, n = data.length; ++i < n;) { - if (compare(get(data, i))) { + if (compare(at(data, i))) { return i; } } @@ -148,10 +148,10 @@ function indexOfUnion(data: Data, searchElement?: T['TVal // If the searchElement is null, we don't know whether it came from the Union's // bitmap or one of its children's. So we don't interrogate the Union's bitmap, // since that will report the wrong index if a child has a null before the Union. - const get = getVisitor.getVisitFn(data); + const at = atVisitor.getVisitFn(data); const compare = createElementComparator(searchElement); for (let i = (fromIndex || 0) - 1, n = data.length; ++i < n;) { - if (compare(get(data, i))) { + if (compare(at(data, i))) { return i; } } diff --git a/js/src/visitor/iterator.ts b/js/src/visitor/iterator.ts index bf7e9d1591b40..ce6d3bc471aae 100644 --- a/js/src/visitor/iterator.ts +++ b/js/src/visitor/iterator.ts @@ -132,7 +132,7 @@ class VectorIterator implements IterableIterator { if (this.index < this.vector.length) { return { - value: this.vector.get(this.index++) + value: this.vector.at(this.index++) }; } diff --git a/js/src/visitor/set.ts b/js/src/visitor/set.ts index eb1f280964c8e..bef63416bc622 100644 --- a/js/src/visitor/set.ts +++ b/js/src/visitor/set.ts @@ -229,7 +229,7 @@ const setList = (data: Data, index: number, value: T['TValue' } } else { for (let idx = -1, itr = valueOffsets[index], end = valueOffsets[index + 1]; itr < end;) { - set(values, itr++, value.get(++idx)); + set(values, itr++, value.at(++idx)); } } }; @@ -253,7 +253,7 @@ const setMap = (data: Data, index: number, value: T['TValue'] (set: SetFunc, c: Data, _: Field, i: number) => c && set(c, o, v[i]); /** @ignore */ const _setStructVectorValue = (o: number, v: Vector) => - (set: SetFunc, c: Data, _: Field, i: number) => c && set(c, o, v.get(i)); + (set: SetFunc, c: Data, _: Field, i: number) => c && set(c, o, v.at(i)); /** @ignore */ const _setStructMapValue = (o: number, v: Map) => (set: SetFunc, c: Data, f: Field, _: number) => c && set(c, o, v.get(f.name)); @@ -347,7 +347,7 @@ const setFixedSizeList = (data: Data, index: number, } } else { for (let idx = -1, offset = index * stride; ++idx < stride;) { - set(child, offset + idx, value.get(idx)); + set(child, offset + idx, value.at(idx)); } } }; diff --git a/js/test/inference/column.ts b/js/test/inference/column.ts index 35659084c35a2..9a059682e8259 100644 --- a/js/test/inference/column.ts +++ b/js/test/inference/column.ts @@ -38,8 +38,8 @@ const boolColumn = new Vector([ new Vector([makeData({ type: boolType, length: 10, nullCount: 0, data: new Uint8Array(2) })]), ]); -expect(typeof boolVector.get(0) === 'boolean').toBe(true); -expect(typeof boolColumn.get(0) === 'boolean').toBe(true); +expect(typeof boolVector.at(0) === 'boolean').toBe(true); +expect(typeof boolColumn.at(0) === 'boolean').toBe(true); type IndexSchema = { 0: Int8; @@ -61,8 +61,8 @@ const structColumn = new Vector([ new Vector([makeData({ type: structType, length: 0, nullCount: 0, children: [] })]), ]); -const [x1, y1, z1] = structVector.get(0)!; -const [x2, y2, z2] = structColumn.get(0)!; +const [x1, y1, z1] = structVector.at(0)!; +const [x2, y2, z2] = structColumn.at(0)!; console.log(x1, y1, z1); console.log(x2, y2, z2); diff --git a/js/test/inference/nested.ts b/js/test/inference/nested.ts index 2cc768ca4d057..f9de3030f618a 100644 --- a/js/test/inference/nested.ts +++ b/js/test/inference/nested.ts @@ -42,7 +42,7 @@ function checkIndexTypes(schema: IndexSchema) { length: 0, offset: 0, nullCount: 0, nullBitmap: null, children: [] }); - const row = new Vector([data]).get(0)!; + const row = new Vector([data]).at(0)!; const check_0 = (x = row[0]) => expect(typeof x === 'number').toBe(true); const check_1 = (x = row[1]) => expect(typeof x === 'string').toBe(true); @@ -64,7 +64,7 @@ function checkNamedTypes(schema: NamedSchema) { length: 0, offset: 0, nullCount: 0, nullBitmap: null, children: [] }); - const row = new Vector([data]).get(0)!; + const row = new Vector([data]).at(0)!; const check_a = (x = row.a) => expect(typeof x === 'number').toBe(true); const check_b = (x = row.b) => expect(typeof x === 'string').toBe(true); diff --git a/js/test/inference/visitor/get.ts b/js/test/inference/visitor/at.ts similarity index 51% rename from js/test/inference/visitor/get.ts rename to js/test/inference/visitor/at.ts index ab9727b59d3f7..5082a8f0b2ad3 100644 --- a/js/test/inference/visitor/get.ts +++ b/js/test/inference/visitor/at.ts @@ -20,7 +20,7 @@ import { Bool, List, Dictionary } from 'apache-arrow'; -import { instance as getVisitor } from 'apache-arrow/visitor/get'; +import { instance as atVisitor } from 'apache-arrow/visitor/at'; const data_Bool = new Data(new Bool(), 0, 0); const data_List_Bool = new Data(new List(null as any), 0, 0); @@ -29,48 +29,48 @@ const data_Dictionary_List_Bool = new Data(new Dictionary>(null!, nul const boolVec = new Vector([data_Bool]); // @ts-ignore -const boolVec_getRaw = boolVec.get(0); +const boolVec_getRaw = boolVec.at(0); // @ts-ignore -const boolVec_getVisit = getVisitor.visit(boolVec.data[0], 0); +const boolVec_getVisit = atVisitor.visit(boolVec.data[0], 0); // @ts-ignore -const boolVec_getFactory = getVisitor.getVisitFn(boolVec)(boolVec.data[0], 0); +const boolVec_getFactory = atVisitor.getVisitFn(boolVec)(boolVec.data[0], 0); // @ts-ignore -const boolVec_getFactoryData = getVisitor.getVisitFn(boolVec.data[0])(boolVec.data[0], 0); +const boolVec_getFactoryData = atVisitor.getVisitFn(boolVec.data[0])(boolVec.data[0], 0); // @ts-ignore -const boolVec_getFactoryType = getVisitor.getVisitFn(boolVec.type)(boolVec.data[0], 0); +const boolVec_getFactoryType = atVisitor.getVisitFn(boolVec.type)(boolVec.data[0], 0); const listVec = new Vector([data_List_Bool]); // @ts-ignore -const listVec_getRaw = listVec.get(0); +const listVec_getRaw = listVec.at(0); // @ts-ignore -const listVec_getVisit = getVisitor.visit(listVec.data[0], 0); +const listVec_getVisit = atVisitor.visit(listVec.data[0], 0); // @ts-ignore -const listVec_getFactory = getVisitor.getVisitFn(listVec)(listVec.data[0], 0); +const listVec_getFactory = atVisitor.getVisitFn(listVec)(listVec.data[0], 0); // @ts-ignore -const listVec_getFactoryData = getVisitor.getVisitFn(listVec.data[0])(listVec.data[0], 0); +const listVec_getFactoryData = atVisitor.getVisitFn(listVec.data[0])(listVec.data[0], 0); // @ts-ignore -const listVec_getFactoryType = getVisitor.getVisitFn(listVec.type)(listVec.data[0], 0); +const listVec_getFactoryType = atVisitor.getVisitFn(listVec.type)(listVec.data[0], 0); const dictVec = new Vector([data_Dictionary_Bool]); // @ts-ignore -const dictVec_getRaw = dictVec.get(0); +const dictVec_getRaw = dictVec.at(0); // @ts-ignore -const dictVec_getVisit = getVisitor.visit(dictVec.data[0], 0); +const dictVec_getVisit = atVisitor.visit(dictVec.data[0], 0); // @ts-ignore -const dictVec_getFactory = getVisitor.getVisitFn(dictVec)(dictVec.data[0], 0); +const dictVec_getFactory = atVisitor.atVisitFn(dictVec)(dictVec.data[0], 0); // @ts-ignore -const dictVec_getFactoryData = getVisitor.getVisitFn(dictVec.data[0])(dictVec.data[0], 0); +const dictVec_getFactoryData = atVisitor.getVisitFn(dictVec.data[0])(dictVec.data[0], 0); // @ts-ignore -const dictVec_getFactoryType = getVisitor.getVisitFn(dictVec.type)(dictVec.data[0], 0); +const dictVec_getFactoryType = atVisitor.getVisitFn(dictVec.type)(dictVec.data[0], 0); const dictOfListVec = new Vector([data_Dictionary_List_Bool]); // @ts-ignore -const dictOfListVec_getRaw = dictOfListVec.get(0); +const dictOfListVec_getRaw = dictOfListVec.at(0); // @ts-ignore -const dictOfListVec_getVisit = getVisitor.visit(dictOfListVec.data[0], 0); +const dictOfListVec_getVisit = atVisitor.visit(dictOfListVec.data[0], 0); // @ts-ignore -const dictOfListVec_getFactory = getVisitor.getVisitFn(dictOfListVec)(dictOfListVec.data[0], 0); +const dictOfListVec_getFactory = atVisitor.getVisitFn(dictOfListVec)(dictOfListVec.data[0], 0); // @ts-ignore -const dictOfListVec_getFactoryData = getVisitor.getVisitFn(dictOfListVec.data[0])(dictOfListVec.data[0], 0); +const dictOfListVec_getFactoryData = atVisitor.getVisitFn(dictOfListVec.data[0])(dictOfListVec.data[0], 0); // @ts-ignore -const dictOfListVec_getFactoryType = getVisitor.getVisitFn(dictOfListVec.type)(dictOfListVec.data[0], 0); +const dictOfListVec_getFactoryType = atVisitor.getVisitFn(dictOfListVec.type)(dictOfListVec.data[0], 0); diff --git a/js/test/jest-extensions.ts b/js/test/jest-extensions.ts index cb97ae2590797..8a5e0ad782ddb 100644 --- a/js/test/jest-extensions.ts +++ b/js/test/jest-extensions.ts @@ -124,7 +124,7 @@ function toEqualVector< } } for (let i = -1, n = v1.length; ++i < n;) { - const x1 = v1.get(i), x2 = v2.get(i); + const x1 = v1.at(i), x2 = v2.at(i); if (!util.createElementComparator(x2)(x1)) { getFailures.push(`${i}: ${format(this, x1, x2, ' !== ')}`); } diff --git a/js/test/unit/bn-tests.ts b/js/test/unit/bn-tests.ts index c9606baf85942..56f2e043d50d5 100644 --- a/js/test/unit/bn-tests.ts +++ b/js/test/unit/bn-tests.ts @@ -71,7 +71,7 @@ describe(`BN`, () => { nullValues: [] }); builder.append(val); - return builder.finish().toVector().get(0); + return builder.finish().toVector().at(0); }; const d2 = toDecimal(new Uint32Array([0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF])); diff --git a/js/test/unit/builders/utils.ts b/js/test/unit/builders/utils.ts index db4e80d002778..fe32fd2ff5ad1 100644 --- a/js/test/unit/builders/utils.ts +++ b/js/test/unit/builders/utils.ts @@ -166,7 +166,7 @@ export function validateVector(vals: (T['TValue'] | null)[], } catch (e: any) { // Uncomment these two lines to catch and debug the value retrieval that failed // debugger; - // vec.get(i); + // vec.at(i); throw new Error([ `${(vec as any).VectorName}[${i}]: ${e?.stack || e}`, `nulls: [${nullVals.join(', ')}]`, diff --git a/js/test/unit/generated-data-validators.ts b/js/test/unit/generated-data-validators.ts index 57ee94876c300..c9bde74782a81 100644 --- a/js/test/unit/generated-data-validators.ts +++ b/js/test/unit/generated-data-validators.ts @@ -109,7 +109,7 @@ function vectorTests(values: any[], vector: Vector, keys?: number[]) { let i = -1, n = vector.length, actual, expected; try { while (++i < n) { - actual = vector.get(i); + actual = vector.at(i); expected = values[i]; expect(actual).toArrowCompare(expected); } @@ -125,8 +125,8 @@ function vectorTests(values: any[], vector: Vector, keys?: number[]) { try { while (++i < n) { indices.isValid(i) - ? expect(indices.get(i)).toBe(keys[i]) - : expect(indices.get(i)).toBeNull(); + ? expect(indices.at(i)).toBe(keys[i]) + : expect(indices.at(i)).toBeNull(); } } catch (e) { throw new Error(`${indices}[${i}]: ${e}`); @@ -140,7 +140,7 @@ function vectorTests(values: any[], vector: Vector, keys?: number[]) { while (++i < n) { expected = values[i]; vector.set(i, expected); - actual = vector.get(i); + actual = vector.at(i); expect(actual).toArrowCompare(expected); } } catch (e: any) { diff --git a/js/test/unit/table-tests.ts b/js/test/unit/table-tests.ts index 3f12905a92bdf..3118dfd234bf8 100644 --- a/js/test/unit/table-tests.ts +++ b/js/test/unit/table-tests.ts @@ -317,7 +317,7 @@ describe(`Table`, () => { const table = datum.table(); const values = datum.values(); for (let i = -1; ++i < values.length;) { - const row = table.get(i)!; + const row = table.at(i)!; expect(row).not.toBeNull(); const expected = values[i]; expect(row.f32).toEqual(expected[F32]); diff --git a/js/test/unit/vector/bool-vector-tests.ts b/js/test/unit/vector/bool-vector-tests.ts index afbaef01a1a45..724d5ce735714 100644 --- a/js/test/unit/vector/bool-vector-tests.ts +++ b/js/test/unit/vector/bool-vector-tests.ts @@ -27,7 +27,7 @@ describe(`BoolVector`, () => { test(`gets expected values`, () => { let i = -1; while (++i < n) { - expect(vector.get(i)).toEqual(values[i]); + expect(vector.at(i)).toEqual(values[i]); } }); test(`iterates expected values`, () => { @@ -54,7 +54,7 @@ describe(`BoolVector`, () => { const expected3 = [true, true, false, false, false, false, true, true]; function validate(expected: boolean[]) { for (let i = -1; ++i < n;) { - expect(v.get(i)).toEqual(expected[i]); + expect(v.at(i)).toEqual(expected[i]); } } validate(expected1); diff --git a/js/test/unit/vector/numeric-vector-tests.ts b/js/test/unit/vector/numeric-vector-tests.ts index 032af796de138..22e62e12e6034 100644 --- a/js/test/unit/vector/numeric-vector-tests.ts +++ b/js/test/unit/vector/numeric-vector-tests.ts @@ -340,7 +340,7 @@ function gets_expected_values(vector: Vector, typed: T let i = -1, n = vector.length; try { while (++i < n) { - expect(vector.get(i)).toEqual(values[i]); + expect(vector.at(i)).toEqual(values[i]); } } catch (e) { throw new Error(`${i}: ${e}`); } }); diff --git a/js/test/unit/vector/vector-tests.ts b/js/test/unit/vector/vector-tests.ts index bfcf0d8547861..9a52edd6d3f4d 100644 --- a/js/test/unit/vector/vector-tests.ts +++ b/js/test/unit/vector/vector-tests.ts @@ -73,7 +73,7 @@ describe(`StructVector`, () => { test(`get value`, () => { for (const [i, value] of values.entries()) { - expect(vector.get(i)!.toJSON()).toEqual(value); + expect(vector.at(i)!.toJSON()).toEqual(value); } }); }); @@ -228,7 +228,7 @@ describe(`ListVector`, () => { test(`get value`, () => { for (const [i, value] of values.entries()) { - expect(vector.get(i)!.toJSON()).toEqual(value); + expect(vector.at(i)!.toJSON()).toEqual(value); } }); }); @@ -272,7 +272,7 @@ function basicVectorTests(vector: Vector, values: any[], extras: any[]) { test(`gets expected values`, () => { let i = -1; while (++i < n) { - expect(vector.get(i)).toEqual(values[i]); + expect(vector.at(i)).toEqual(values[i]); } }); test(`iterates expected values`, () => { From 27cea44405e97aa74206394320d1c87fb5ca3765 Mon Sep 17 00:00:00 2001 From: Dominik Moritz Date: Thu, 21 Mar 2024 11:37:53 -0400 Subject: [PATCH 2/2] Support negative indexes --- js/src/util/chunk.ts | 6 +++ js/src/vector.ts | 12 ++++-- js/test/unit/vector/bool-vector-tests.ts | 8 ++-- js/test/unit/vector/numeric-vector-tests.ts | 7 ++-- js/test/unit/vector/vector-tests.ts | 43 ++++++++++++++------- 5 files changed, 52 insertions(+), 24 deletions(-) diff --git a/js/src/util/chunk.ts b/js/src/util/chunk.ts index 36620627f197d..ef0b28a991155 100644 --- a/js/src/util/chunk.ts +++ b/js/src/util/chunk.ts @@ -120,6 +120,9 @@ export function isChunkedValid(data: Data, index: number) export function wrapChunkedCall1(fn: (c: Data, _1: number) => any) { function chunkedFn(chunks: ReadonlyArray>, i: number, j: number) { return fn(chunks[i], j); } return function (this: any, index: number) { + // negative indexes count from the back + if (index < 0) index += this.length; + const data = this.data as ReadonlyArray>; return binarySearch(data, this._offsets, index, chunkedFn); }; @@ -130,6 +133,9 @@ export function wrapChunkedCall2(fn: (c: Data, _1: number let _2: any; function chunkedFn(chunks: ReadonlyArray>, i: number, j: number) { return fn(chunks[i], j, _2); } return function (this: any, index: number, value: any) { + // negative indexes count from the back + if (index < 0) index += this.length; + const data = this.data as ReadonlyArray>; _2 = value; const result = binarySearch(data, this._offsets, index, chunkedFn); diff --git a/js/src/vector.ts b/js/src/vector.ts index 5a0bdb1742ddd..6bf8fdcb139ea 100644 --- a/js/src/vector.ts +++ b/js/src/vector.ts @@ -78,9 +78,9 @@ export class Vector { const { at, set, indexOf } = visitorsByTypeId[type.typeId]; const unchunkedData = data[0]; - this.isValid = (index: number) => isChunkedValid(unchunkedData, index); - this.at = (index: number) => at(unchunkedData, index); - this.set = (index: number, value: T) => set(unchunkedData, index, value); + this.isValid = (index: number) => isChunkedValid(unchunkedData, index < 0 ? index + this.length : index); + this.at = (index: number) => at(unchunkedData, index < 0 ? index + this.length : index); + this.set = (index: number, value: T) => set(unchunkedData, index < 0 ? index + this.length : index, value); this.indexOf = (index: number) => indexOf(unchunkedData, index); this._offsets = [0, unchunkedData.length]; break; @@ -395,6 +395,9 @@ class MemoizedVector extends Vector { Object.defineProperty(this, 'at', { value(index: number) { + // negative indexes count from the back + if (index < 0) index += this.length; + const cachedValue = cache[index]; if (cachedValue !== undefined) { return cachedValue; @@ -407,6 +410,9 @@ class MemoizedVector extends Vector { Object.defineProperty(this, 'set', { value(index: number, value: T['TValue'] | null) { + // negative indexes count from the back + if (index < 0) index += this.length; + set.call(this, index, value); cache[index] = value; } diff --git a/js/test/unit/vector/bool-vector-tests.ts b/js/test/unit/vector/bool-vector-tests.ts index 724d5ce735714..5e032933683e6 100644 --- a/js/test/unit/vector/bool-vector-tests.ts +++ b/js/test/unit/vector/bool-vector-tests.ts @@ -25,9 +25,9 @@ describe(`BoolVector`, () => { const n = values.length; const vector = newBoolVector(n, new Uint8Array([27, 0, 0, 0, 0, 0, 0, 0])); test(`gets expected values`, () => { - let i = -1; - while (++i < n) { - expect(vector.at(i)).toEqual(values[i]); + for (let i = 0; i < values.length; i++) { + expect(vector.at(i)).toEqual(values.at(i)); + expect(vector.at(-i)).toEqual(values.at(-i)); } }); test(`iterates expected values`, () => { @@ -53,7 +53,7 @@ describe(`BoolVector`, () => { const expected2 = [true, true, true, true, true, false, false, false]; const expected3 = [true, true, false, false, false, false, true, true]; function validate(expected: boolean[]) { - for (let i = -1; ++i < n;) { + for (let i = 0; i < n; i++) { expect(v.at(i)).toEqual(expected[i]); } } diff --git a/js/test/unit/vector/numeric-vector-tests.ts b/js/test/unit/vector/numeric-vector-tests.ts index 22e62e12e6034..99f72a1852515 100644 --- a/js/test/unit/vector/numeric-vector-tests.ts +++ b/js/test/unit/vector/numeric-vector-tests.ts @@ -337,10 +337,11 @@ function testAndValidateVector(vector: Vector, typed: function gets_expected_values(vector: Vector, typed: T['TArray'], values: any[] = [...typed]) { test(`gets expected values`, () => { expect.hasAssertions(); - let i = -1, n = vector.length; + let i = -1; try { - while (++i < n) { - expect(vector.at(i)).toEqual(values[i]); + while (++i < vector.length) { + expect(vector.at(i)).toEqual(values.at(i)); + expect(vector.at(-i)).toEqual(values.at(-i)); } } catch (e) { throw new Error(`${i}: ${e}`); } }); diff --git a/js/test/unit/vector/vector-tests.ts b/js/test/unit/vector/vector-tests.ts index 9a52edd6d3f4d..356838a865b21 100644 --- a/js/test/unit/vector/vector-tests.ts +++ b/js/test/unit/vector/vector-tests.ts @@ -23,7 +23,7 @@ describe(`makeVectorFromArray`, () => { describe(`works with null values`, () => { const values = [1, 2, 3, 4, null, 5]; const vector = vectorFromArray(values); - basicVectorTests(vector, values, []); + basicVectorTests(vector, values, [], false); test(`toArray returns typed array for numbers`, () => { expect(vector.toArray()).toEqual(Float64Array.from(values.map(n => n === null ? 0 : n))); }); @@ -72,8 +72,9 @@ describe(`StructVector`, () => { }); test(`get value`, () => { - for (const [i, value] of values.entries()) { - expect(vector.at(i)!.toJSON()).toEqual(value); + for (let i = 0; i < values.length; i++) { + expect(vector.at(i)!.toJSON()).toEqual(values.at(i)); + expect(vector.at(-i)!.toJSON()).toEqual(values.at(-i)); } }); }); @@ -83,6 +84,7 @@ describe(`DateVector`, () => { new Date(2000, 0, 1), new Date(1991, 5, 28, 12, 11, 10) ]; + describe(`unit = MILLISECOND`, () => { const values = [ new Date(1989, 5, 22, 1, 2, 3), @@ -93,6 +95,7 @@ describe(`DateVector`, () => { const vector = vectorFromArray(values, new DateMillisecond); basicVectorTests(vector, values, extras); }); + describe(`unit = DAY`, () => { // Use UTC to ensure that dates are always at midnight const values = [ @@ -146,9 +149,9 @@ describe(`DictionaryVector`, () => { type: new Dictionary(dictionary_vec.type, new Int32) }); - basicVectorTests(vector, values, ['abc', '123']); + basicVectorTests(vector, values, ['abc', '123'], false); describe(`sliced`, () => { - basicVectorTests(vector.slice(10, 20), values.slice(10, 20), extras); + basicVectorTests(vector.slice(10, 20), values.slice(10, 20), extras, false); }); }); @@ -226,9 +229,10 @@ describe(`ListVector`, () => { expect(vector.type).toBeInstanceOf(List); }); - test(`get value`, () => { - for (const [i, value] of values.entries()) { - expect(vector.at(i)!.toJSON()).toEqual(value); + test(`at value`, () => { + for (let i = 0; i < values.length; i++) { + expect(vector.at(i)!.toJSON()).toEqual(values.at(i)); + expect(vector.at(-i)!.toJSON()).toEqual(values.at(-i)); } }); }); @@ -263,18 +267,28 @@ describe(`toArray()`, () => { // Creates some basic tests for the given vector. // Verifies that: -// - `get` and the native iterator return the same data as `values` +// - `at` and the native iterator return the same data as `values` // - `indexOf` returns the same indices as `values` -function basicVectorTests(vector: Vector, values: any[], extras: any[]) { +function basicVectorTests(vector: Vector, values: any[], extras: any[], testValid = true) { const n = values.length; - test(`gets expected values`, () => { - let i = -1; - while (++i < n) { - expect(vector.at(i)).toEqual(values[i]); + test(`at expected values`, () => { + for (let i = 0; i < values.length; i++) { + expect(vector.at(i)).toEqual(values.at(i)); + expect(vector.at(-i)).toEqual(values.at(-i)); } }); + + test(`isValid expected values`, () => { + if (testValid) { + for (let i = 0; i < values.length; i++) { + expect(vector.isValid(i)).toBeTruthy(); + expect(vector.isValid(-i)).toBeTruthy(); + } + } + }); + test(`iterates expected values`, () => { expect.hasAssertions(); let i = -1; @@ -283,6 +297,7 @@ function basicVectorTests(vector: Vector, values: any[], extras: any[]) { expect(v).toEqual(values[i]); } }); + test(`indexOf returns expected values`, () => { const testValues = values.concat(extras);