blob: bbaa0991a456905b320ab76d83017a0641cbaef8 [file] [log] [blame]
// Copyright (C) 2023 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import {isString} from './object_utils';
export type ComparisonFn<X> = (a: X, b: X) => number;
export type SortDirection = 'DESC' | 'ASC';
// Having a comparison function of type S and a getter that returns value of
// type S from value of type T, values of type T can be compared.
export function comparingBy<T, S>(
getter: (t: T) => S,
comparison: ComparisonFn<S>,
): ComparisonFn<T> {
return (x, y) => {
return comparison(getter(x), getter(y));
};
}
export function withDirection<T>(
comparison: ComparisonFn<T>,
sortDirection?: SortDirection,
): ComparisonFn<T> {
if (sortDirection !== 'DESC') {
return comparison;
}
return (x, y) => {
return comparison(y, x);
};
}
export type SortableValue =
| string
| number
| bigint
| null
| Uint8Array
| undefined;
function columnTypeKind(a: SortableValue): number {
if (a === undefined) {
return 0;
}
if (a === null) {
return 1;
}
if (typeof a === 'number') {
return 2;
}
if (isString(a)) {
return 3;
}
// a instanceof Uint8Array
return 4;
}
export function compareUniversal(a: SortableValue, b: SortableValue): number {
if (a === undefined && b === undefined) {
return 0;
}
if (a === null && b === null) {
return 0;
}
if (typeof a === 'number' && typeof b === 'number') {
return a - b;
}
if (isString(a) && isString(b)) {
return a.localeCompare(b);
}
if (a instanceof Uint8Array && b instanceof Uint8Array) {
// Do the lexicographical comparison
for (let i = 0; i < a.length && i < b.length; i++) {
if (a[i] < b[i]) {
return -1;
}
if (a[i] > b[i]) {
return 1;
}
}
// No discrepancies found in the common prefix, compare lengths of arrays.
return a.length - b.length;
}
// Values are of different kinds, compare the kinds
return columnTypeKind(a) - columnTypeKind(b);
}