]> git.proxmox.com Git - ceph.git/blob - ceph/src/arrow/js/src/util/vector.ts
import quincy 17.2.0
[ceph.git] / ceph / src / arrow / js / src / util / vector.ts
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
18 import { Vector } from '../vector';
19 import { MapRow, StructRow } from '../vector/row';
20 import { compareArrayLike } from '../util/buffer';
21 import { BigInt, BigIntAvailable } from './compat';
22
23 /** @ignore */
24 type RangeLike = { length: number; stride?: number };
25 /** @ignore */
26 type ClampThen<T extends RangeLike> = (source: T, index: number) => any;
27 /** @ignore */
28 type ClampRangeThen<T extends RangeLike> = (source: T, offset: number, length: number) => any;
29
30 export function clampIndex<T extends RangeLike>(source: T, index: number): number;
31 export function clampIndex<T extends RangeLike, N extends ClampThen<T> = ClampThen<T>>(source: T, index: number, then: N): ReturnType<N>;
32 /** @ignore */
33 export function clampIndex<T extends RangeLike, N extends ClampThen<T> = ClampThen<T>>(source: T, index: number, then?: N) {
34 const length = source.length;
35 const adjust = index > -1 ? index : (length + (index % length));
36 return then ? then(source, adjust) : adjust;
37 }
38
39 /** @ignore */
40 let tmp: number;
41 export function clampRange<T extends RangeLike>(source: T, begin: number | undefined, end: number | undefined): [number, number];
42 export function clampRange<T extends RangeLike, N extends ClampRangeThen<T> = ClampRangeThen<T>>(source: T, begin: number | undefined, end: number | undefined, then: N): ReturnType<N>;
43 /** @ignore */
44 export function clampRange<T extends RangeLike, N extends ClampRangeThen<T> = ClampRangeThen<T>>(source: T, begin: number | undefined, end: number | undefined, then?: N) {
45
46 // Adjust args similar to Array.prototype.slice. Normalize begin/end to
47 // clamp between 0 and length, and wrap around on negative indices, e.g.
48 // slice(-1, 5) or slice(5, -1)
49 const { length: len = 0 } = source;
50 let lhs = typeof begin !== 'number' ? 0 : begin;
51 let rhs = typeof end !== 'number' ? len : end;
52 // wrap around on negative start/end positions
53 (lhs < 0) && (lhs = ((lhs % len) + len) % len);
54 (rhs < 0) && (rhs = ((rhs % len) + len) % len);
55 // ensure lhs <= rhs
56 (rhs < lhs) && (tmp = lhs, lhs = rhs, rhs = tmp);
57 // ensure rhs <= length
58 (rhs > len) && (rhs = len);
59
60 return then ? then(source, lhs, rhs) : [lhs, rhs];
61 }
62
63 const big0 = BigIntAvailable ? BigInt(0) : 0;
64 const isNaNFast = (value: any) => value !== value;
65
66 /** @ignore */
67 export function createElementComparator(search: any) {
68 const typeofSearch = typeof search;
69 // Compare primitives
70 if (typeofSearch !== 'object' || search === null) {
71 // Compare NaN
72 if (isNaNFast(search)) {
73 return isNaNFast;
74 }
75 return typeofSearch !== 'bigint'
76 ? (value: any) => value === search
77 : (value: any) => (big0 + value) === search;
78 }
79 // Compare Dates
80 if (search instanceof Date) {
81 const valueOfSearch = search.valueOf();
82 return (value: any) => value instanceof Date ? (value.valueOf() === valueOfSearch) : false;
83 }
84 // Compare TypedArrays
85 if (ArrayBuffer.isView(search)) {
86 return (value: any) => value ? compareArrayLike(search, value) : false;
87 }
88 // Compare Maps and Rows
89 if (search instanceof Map) { return creatMapComparator(search); }
90 // Compare Array-likes
91 if (Array.isArray(search)) { return createArrayLikeComparator(search); }
92 // Compare Vectors
93 if (search instanceof Vector) { return createVectorComparator(search); }
94 // Compare non-empty Objects
95 return createObjectComparator(search);
96 }
97
98 /** @ignore */
99 function createArrayLikeComparator(lhs: ArrayLike<any>) {
100 const comparators = [] as ((x: any) => boolean)[];
101 for (let i = -1, n = lhs.length; ++i < n;) {
102 comparators[i] = createElementComparator(lhs[i]);
103 }
104 return createSubElementsComparator(comparators);
105 }
106
107 /** @ignore */
108 function creatMapComparator(lhs: Map<any, any>) {
109 let i = -1;
110 const comparators = [] as ((x: any) => boolean)[];
111 lhs.forEach((v) => comparators[++i] = createElementComparator(v));
112 return createSubElementsComparator(comparators);
113 }
114
115 /** @ignore */
116 function createVectorComparator(lhs: Vector<any>) {
117 const comparators = [] as ((x: any) => boolean)[];
118 for (let i = -1, n = lhs.length; ++i < n;) {
119 comparators[i] = createElementComparator(lhs.get(i));
120 }
121 return createSubElementsComparator(comparators);
122 }
123
124 /** @ignore */
125 function createObjectComparator(lhs: any) {
126 const keys = Object.keys(lhs);
127 // Only compare non-empty Objects
128 if (keys.length === 0) { return () => false; }
129 const comparators = [] as ((x: any) => boolean)[];
130 for (let i = -1, n = keys.length; ++i < n;) {
131 comparators[i] = createElementComparator(lhs[keys[i]]);
132 }
133 return createSubElementsComparator(comparators, keys);
134 }
135
136 function createSubElementsComparator(comparators: ((x: any) => boolean)[], keys?: Iterable<string>) {
137 return (rhs: any) => {
138 if (!rhs || typeof rhs !== 'object') {
139 return false;
140 }
141 switch (rhs.constructor) {
142 case Array: return compareArray(comparators, rhs);
143 case Map:
144 case MapRow:
145 case StructRow:
146 return compareObject(comparators, rhs, rhs.keys());
147 case Object:
148 case undefined: // support `Object.create(null)` objects
149 return compareObject(comparators, rhs, keys || Object.keys(rhs));
150 }
151 return rhs instanceof Vector ? compareVector(comparators, rhs) : false;
152 };
153 }
154
155 function compareArray(comparators: ((x: any) => boolean)[], arr: any[]) {
156 const n = comparators.length;
157 if (arr.length !== n) { return false; }
158 for (let i = -1; ++i < n;) {
159 if (!(comparators[i](arr[i]))) { return false; }
160 }
161 return true;
162 }
163
164 function compareVector(comparators: ((x: any) => boolean)[], vec: Vector) {
165 const n = comparators.length;
166 if (vec.length !== n) { return false; }
167 for (let i = -1; ++i < n;) {
168 if (!(comparators[i](vec.get(i)))) { return false; }
169 }
170 return true;
171 }
172
173 function compareObject(comparators: ((x: any) => boolean)[], obj: Map<any, any>, keys: Iterable<string>) {
174
175 const lKeyItr = keys[Symbol.iterator]();
176 const rKeyItr = obj instanceof Map ? obj.keys() : Object.keys(obj)[Symbol.iterator]();
177 const rValItr = obj instanceof Map ? obj.values() : Object.values(obj)[Symbol.iterator]();
178
179 let i = 0;
180 const n = comparators.length;
181 let rVal = rValItr.next();
182 let lKey = lKeyItr.next();
183 let rKey = rKeyItr.next();
184
185 for (; i < n && !lKey.done && !rKey.done && !rVal.done;
186 ++i, lKey = lKeyItr.next(), rKey = rKeyItr.next(), rVal = rValItr.next()) {
187 if (lKey.value !== rKey.value || !comparators[i](rVal.value)) {
188 break;
189 }
190 }
191 if (i === n && lKey.done && rKey.done && rVal.done) {
192 return true;
193 }
194 lKeyItr.return && lKeyItr.return();
195 rKeyItr.return && rKeyItr.return();
196 rValItr.return && rValItr.return();
197 return false;
198 }