1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18import { Data } from '../data';
19import { Vector } from '../vector';
20import { Chunked } from './chunked';
21import { BaseVector } from './base';
22import { VectorBuilderOptions } from './index';
23import { vectorFromValuesWithType } from './index';
24import { VectorBuilderOptionsAsync } from './index';
25import { BigInt64Array, BigUint64Array } from '../util/compat';
26import { toBigInt64Array, toBigUint64Array } from '../util/buffer';
27import { Int, Uint8, Uint16, Uint32, Uint64, Int8, Int16, Int32, Int64, IntArray } from '../type';
28import { VectorType as V, TypedArrayConstructor, BigIntArrayConstructor, BigIntArray } from '../interfaces';
29
30/** @ignore */
31type IntVectorConstructors =
32    typeof IntVector    |
33    typeof Int8Vector   |
34    typeof Int16Vector  |
35    typeof Int32Vector  |
36    typeof Uint8Vector  |
37    typeof Uint16Vector |
38    typeof Uint32Vector |
39    typeof Int64Vector  |
40    typeof Uint64Vector ;
41
42/** @ignore */
43type FromInput<T extends Int, TNull = any> =
44    IntArray | BigIntArray              |
45    Iterable<T['TValue'] | TNull>       |
46    AsyncIterable<T['TValue'] | TNull>  |
47    VectorBuilderOptions<T, TNull>      |
48    VectorBuilderOptionsAsync<T, TNull> ;
49
50/** @ignore */
51type FromArgs<T extends Int, TNull = any> = [FromInput<T, TNull>, boolean?];
52
53/** @ignore */
54export type IntArrayCtor = TypedArrayConstructor<IntArray> | BigIntArrayConstructor<BigIntArray>;
55
56/** @ignore */
57export class IntVector<T extends Int = Int> extends BaseVector<T> {
58
59    // Guaranteed zero-copy variants
60    public static from(this: typeof IntVector, input: Int8Array): Int8Vector;
61    public static from(this: typeof IntVector, input: Int16Array): Int16Vector;
62    public static from(this: typeof IntVector, input: Int32Array): Int32Vector;
63    public static from(this: typeof IntVector, input: BigInt64Array): Int64Vector;
64    public static from(this: typeof IntVector, input: Int32Array, is64bit: true): Int64Vector;
65    public static from(this: typeof IntVector, input: Uint8Array): Uint8Vector;
66    public static from(this: typeof IntVector, input: Uint16Array): Uint16Vector;
67    public static from(this: typeof IntVector, input: Uint32Array): Uint32Vector;
68    public static from(this: typeof IntVector, input: BigUint64Array): Uint64Vector;
69    public static from(this: typeof IntVector, input: Uint32Array, is64bit: true): Uint64Vector;
70
71    // Zero-copy if input is a TypedArray of the same type as the
72    // Vector that from is called on, otherwise uses the Builders
73    public static from<TNull = any>(this: typeof Int8Vector,   input: FromInput<Int8, TNull>): Int8Vector;
74    public static from<TNull = any>(this: typeof Int16Vector,  input: FromInput<Int16, TNull>): Int16Vector;
75    public static from<TNull = any>(this: typeof Int32Vector,  input: FromInput<Int32, TNull>): Int32Vector;
76    public static from<TNull = any>(this: typeof Int64Vector,  input: FromInput<Int64, TNull>): Int64Vector;
77    public static from<TNull = any>(this: typeof Uint8Vector,  input: FromInput<Uint8, TNull>): Uint8Vector;
78    public static from<TNull = any>(this: typeof Uint16Vector, input: FromInput<Uint16, TNull>): Uint16Vector;
79    public static from<TNull = any>(this: typeof Uint32Vector, input: FromInput<Uint32, TNull>): Uint32Vector;
80    public static from<TNull = any>(this: typeof Uint64Vector, input: FromInput<Uint64, TNull>): Uint64Vector;
81
82    // Not zero-copy
83    public static from<T extends Int, TNull = any>(this: typeof IntVector, input: Iterable<T['TValue'] | TNull>): V<T>;
84    public static from<T extends Int, TNull = any>(this: typeof IntVector, input: AsyncIterable<T['TValue'] | TNull>): Promise<V<T>>;
85    public static from<T extends Int, TNull = any>(this: typeof IntVector, input: VectorBuilderOptions<T, TNull>): Chunked<T>;
86    public static from<T extends Int, TNull = any>(this: typeof IntVector, input: VectorBuilderOptionsAsync<T, TNull>): Promise<Chunked<T>>;
87    /** @nocollapse */
88    public static from<T extends Int, TNull = any>(this: IntVectorConstructors, ...args: FromArgs<T, TNull>) {
89
90        const [input, is64bit = false] = args;
91        let ArrowType = vectorTypeToDataType(this, is64bit);
92
93        if ((input instanceof ArrayBuffer) || ArrayBuffer.isView(input)) {
94            const InputType = arrayTypeToDataType(input.constructor as IntArrayCtor, is64bit) || ArrowType;
95            // Special case, infer the Arrow DataType from the input if calling the base
96            // IntVector.from with a TypedArray, e.g. `IntVector.from(new Int32Array())`
97            if (ArrowType === null) {
98                ArrowType = InputType;
99            }
100            // If the DataType inferred from the Vector constructor matches the
101            // DataType inferred from the input arguments, return zero-copy view
102            if (ArrowType && ArrowType === InputType) {
103                const type = new ArrowType();
104                let length = input.byteLength / type.ArrayType.BYTES_PER_ELEMENT;
105                // If the ArrowType is 64bit but the input type is 32bit pairs, update the logical length
106                if (convert32To64Bit(ArrowType, input.constructor)) {
107                    length *= 0.5;
108                }
109                return Vector.new(Data.Int(type, 0, length, 0, null, input as IntArray));
110            }
111        }
112
113        if (ArrowType) {
114            // If the DataType inferred from the Vector constructor is different than
115            // the DataType inferred from the input TypedArray, or if input isn't a
116            // TypedArray, use the Builders to construct the result Vector
117            return vectorFromValuesWithType(() => new ArrowType!() as T, input);
118        }
119
120        if ((input instanceof DataView) || (input instanceof ArrayBuffer)) {
121            throw new TypeError(`Cannot infer integer type from instance of ${input.constructor.name}`);
122        }
123
124        throw new TypeError('Unrecognized IntVector input');
125    }
126}
127
128/** @ignore */
129export class Int8Vector extends IntVector<Int8> {}
130/** @ignore */
131export class Int16Vector extends IntVector<Int16> {}
132/** @ignore */
133export class Int32Vector extends IntVector<Int32> {}
134/** @ignore */
135export class Int64Vector extends IntVector<Int64> {
136    public toBigInt64Array() {
137        return toBigInt64Array(this.values);
138    }
139    private _values64!: BigInt64Array;
140    public get values64(): BigInt64Array {
141        return this._values64 || (this._values64 = this.toBigInt64Array());
142    }
143}
144
145/** @ignore */
146export class Uint8Vector extends IntVector<Uint8> {}
147/** @ignore */
148export class Uint16Vector extends IntVector<Uint16> {}
149/** @ignore */
150export class Uint32Vector extends IntVector<Uint32> {}
151/** @ignore */
152export class Uint64Vector extends IntVector<Uint64> {
153    public toBigUint64Array() {
154        return toBigUint64Array(this.values);
155    }
156    private _values64!: BigUint64Array;
157    public get values64(): BigUint64Array {
158        return this._values64 || (this._values64 = this.toBigUint64Array());
159    }
160}
161
162const convert32To64Bit = (typeCtor: any, dataCtor: any) => {
163    return (typeCtor === Int64 || typeCtor === Uint64) &&
164           (dataCtor === Int32Array || dataCtor === Uint32Array);
165};
166
167/** @ignore */
168const arrayTypeToDataType = (ctor: IntArrayCtor, is64bit: boolean) => {
169    switch (ctor) {
170        case Int8Array:      return Int8;
171        case Int16Array:     return Int16;
172        case Int32Array:     return is64bit ? Int64 : Int32;
173        case BigInt64Array:  return Int64;
174        case Uint8Array:     return Uint8;
175        case Uint16Array:    return Uint16;
176        case Uint32Array:    return is64bit ? Uint64 : Uint32;
177        case BigUint64Array: return Uint64;
178        default: return null;
179    }
180};
181
182/** @ignore */
183const vectorTypeToDataType = (ctor: IntVectorConstructors, is64bit: boolean) => {
184    switch (ctor) {
185        case Int8Vector:   return Int8;
186        case Int16Vector:  return Int16;
187        case Int32Vector:  return is64bit ? Int64 : Int32;
188        case Int64Vector:  return Int64;
189        case Uint8Vector:  return Uint8;
190        case Uint16Vector: return Uint16;
191        case Uint32Vector: return is64bit ? Uint64 : Uint32;
192        case Uint64Vector: return Uint64;
193        default: return null;
194    }
195};
196