xref: /aosp_15_r20/external/perfetto/ui/src/base/comparison_utils.ts (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1*6dbdd20aSAndroid Build Coastguard Worker// Copyright (C) 2023 The Android Open Source Project
2*6dbdd20aSAndroid Build Coastguard Worker//
3*6dbdd20aSAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*6dbdd20aSAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*6dbdd20aSAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*6dbdd20aSAndroid Build Coastguard Worker//
7*6dbdd20aSAndroid Build Coastguard Worker//      http://www.apache.org/licenses/LICENSE-2.0
8*6dbdd20aSAndroid Build Coastguard Worker//
9*6dbdd20aSAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*6dbdd20aSAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*6dbdd20aSAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*6dbdd20aSAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*6dbdd20aSAndroid Build Coastguard Worker// limitations under the License.
14*6dbdd20aSAndroid Build Coastguard Worker
15*6dbdd20aSAndroid Build Coastguard Workerimport {isString} from './object_utils';
16*6dbdd20aSAndroid Build Coastguard Worker
17*6dbdd20aSAndroid Build Coastguard Workerexport type ComparisonFn<X> = (a: X, b: X) => number;
18*6dbdd20aSAndroid Build Coastguard Worker
19*6dbdd20aSAndroid Build Coastguard Workerexport type SortDirection = 'DESC' | 'ASC';
20*6dbdd20aSAndroid Build Coastguard Worker
21*6dbdd20aSAndroid Build Coastguard Worker// Having a comparison function of type S and a getter that returns value of
22*6dbdd20aSAndroid Build Coastguard Worker// type S from value of type T, values of type T can be compared.
23*6dbdd20aSAndroid Build Coastguard Workerexport function comparingBy<T, S>(
24*6dbdd20aSAndroid Build Coastguard Worker  getter: (t: T) => S,
25*6dbdd20aSAndroid Build Coastguard Worker  comparison: ComparisonFn<S>,
26*6dbdd20aSAndroid Build Coastguard Worker): ComparisonFn<T> {
27*6dbdd20aSAndroid Build Coastguard Worker  return (x, y) => {
28*6dbdd20aSAndroid Build Coastguard Worker    return comparison(getter(x), getter(y));
29*6dbdd20aSAndroid Build Coastguard Worker  };
30*6dbdd20aSAndroid Build Coastguard Worker}
31*6dbdd20aSAndroid Build Coastguard Worker
32*6dbdd20aSAndroid Build Coastguard Workerexport function withDirection<T>(
33*6dbdd20aSAndroid Build Coastguard Worker  comparison: ComparisonFn<T>,
34*6dbdd20aSAndroid Build Coastguard Worker  sortDirection?: SortDirection,
35*6dbdd20aSAndroid Build Coastguard Worker): ComparisonFn<T> {
36*6dbdd20aSAndroid Build Coastguard Worker  if (sortDirection !== 'DESC') {
37*6dbdd20aSAndroid Build Coastguard Worker    return comparison;
38*6dbdd20aSAndroid Build Coastguard Worker  }
39*6dbdd20aSAndroid Build Coastguard Worker
40*6dbdd20aSAndroid Build Coastguard Worker  return (x, y) => {
41*6dbdd20aSAndroid Build Coastguard Worker    return comparison(y, x);
42*6dbdd20aSAndroid Build Coastguard Worker  };
43*6dbdd20aSAndroid Build Coastguard Worker}
44*6dbdd20aSAndroid Build Coastguard Worker
45*6dbdd20aSAndroid Build Coastguard Workerexport type SortableValue =
46*6dbdd20aSAndroid Build Coastguard Worker  | string
47*6dbdd20aSAndroid Build Coastguard Worker  | number
48*6dbdd20aSAndroid Build Coastguard Worker  | bigint
49*6dbdd20aSAndroid Build Coastguard Worker  | null
50*6dbdd20aSAndroid Build Coastguard Worker  | Uint8Array
51*6dbdd20aSAndroid Build Coastguard Worker  | undefined;
52*6dbdd20aSAndroid Build Coastguard Worker
53*6dbdd20aSAndroid Build Coastguard Workerfunction columnTypeKind(a: SortableValue): number {
54*6dbdd20aSAndroid Build Coastguard Worker  if (a === undefined) {
55*6dbdd20aSAndroid Build Coastguard Worker    return 0;
56*6dbdd20aSAndroid Build Coastguard Worker  }
57*6dbdd20aSAndroid Build Coastguard Worker  if (a === null) {
58*6dbdd20aSAndroid Build Coastguard Worker    return 1;
59*6dbdd20aSAndroid Build Coastguard Worker  }
60*6dbdd20aSAndroid Build Coastguard Worker  if (typeof a === 'number') {
61*6dbdd20aSAndroid Build Coastguard Worker    return 2;
62*6dbdd20aSAndroid Build Coastguard Worker  }
63*6dbdd20aSAndroid Build Coastguard Worker  if (isString(a)) {
64*6dbdd20aSAndroid Build Coastguard Worker    return 3;
65*6dbdd20aSAndroid Build Coastguard Worker  }
66*6dbdd20aSAndroid Build Coastguard Worker  // a instanceof Uint8Array
67*6dbdd20aSAndroid Build Coastguard Worker  return 4;
68*6dbdd20aSAndroid Build Coastguard Worker}
69*6dbdd20aSAndroid Build Coastguard Worker
70*6dbdd20aSAndroid Build Coastguard Workerexport function compareUniversal(a: SortableValue, b: SortableValue): number {
71*6dbdd20aSAndroid Build Coastguard Worker  if (a === undefined && b === undefined) {
72*6dbdd20aSAndroid Build Coastguard Worker    return 0;
73*6dbdd20aSAndroid Build Coastguard Worker  }
74*6dbdd20aSAndroid Build Coastguard Worker  if (a === null && b === null) {
75*6dbdd20aSAndroid Build Coastguard Worker    return 0;
76*6dbdd20aSAndroid Build Coastguard Worker  }
77*6dbdd20aSAndroid Build Coastguard Worker  if (typeof a === 'number' && typeof b === 'number') {
78*6dbdd20aSAndroid Build Coastguard Worker    return a - b;
79*6dbdd20aSAndroid Build Coastguard Worker  }
80*6dbdd20aSAndroid Build Coastguard Worker  if (isString(a) && isString(b)) {
81*6dbdd20aSAndroid Build Coastguard Worker    return a.localeCompare(b);
82*6dbdd20aSAndroid Build Coastguard Worker  }
83*6dbdd20aSAndroid Build Coastguard Worker  if (a instanceof Uint8Array && b instanceof Uint8Array) {
84*6dbdd20aSAndroid Build Coastguard Worker    // Do the lexicographical comparison
85*6dbdd20aSAndroid Build Coastguard Worker    for (let i = 0; i < a.length && i < b.length; i++) {
86*6dbdd20aSAndroid Build Coastguard Worker      if (a[i] < b[i]) {
87*6dbdd20aSAndroid Build Coastguard Worker        return -1;
88*6dbdd20aSAndroid Build Coastguard Worker      }
89*6dbdd20aSAndroid Build Coastguard Worker      if (a[i] > b[i]) {
90*6dbdd20aSAndroid Build Coastguard Worker        return 1;
91*6dbdd20aSAndroid Build Coastguard Worker      }
92*6dbdd20aSAndroid Build Coastguard Worker    }
93*6dbdd20aSAndroid Build Coastguard Worker    // No discrepancies found in the common prefix, compare lengths of arrays.
94*6dbdd20aSAndroid Build Coastguard Worker    return a.length - b.length;
95*6dbdd20aSAndroid Build Coastguard Worker  }
96*6dbdd20aSAndroid Build Coastguard Worker
97*6dbdd20aSAndroid Build Coastguard Worker  // Values are of different kinds, compare the kinds
98*6dbdd20aSAndroid Build Coastguard Worker  return columnTypeKind(a) - columnTypeKind(b);
99*6dbdd20aSAndroid Build Coastguard Worker}
100