Preserves ordering
This commit is contained in:
parent
9420cc7236
commit
897fc13054
|
@ -0,0 +1,105 @@
|
|||
import { is, isAnnotated } from './is';
|
||||
import { Bytes } from './bytes';
|
||||
import { Set, Dictionary } from './dictionary';
|
||||
import { Embedded, isEmbedded } from './embedded';
|
||||
import { Float } from './float';
|
||||
import { Value } from './values';
|
||||
import { Record } from './record';
|
||||
|
||||
export function typeCode<V>(v: Value<V>): number {
|
||||
if (isAnnotated<V>(v)) v = v.item;
|
||||
switch (typeof v) {
|
||||
case 'boolean':
|
||||
return 0;
|
||||
case 'number':
|
||||
case 'bigint':
|
||||
return 3;
|
||||
case 'string':
|
||||
return 4;
|
||||
case 'symbol':
|
||||
return 6;
|
||||
case 'object':
|
||||
if (Float.isFloat(v)) {
|
||||
return Float.isSingle(v) ? 1 : 2;
|
||||
}
|
||||
if (Bytes.isBytes(v)) return 5;
|
||||
if (Array.isArray(v)) {
|
||||
return ('label' in v) ? 7 : 8;
|
||||
}
|
||||
if (Set.isSet<V>(v)) return 9;
|
||||
if (Dictionary.isDictionary<V>(v)) return 10;
|
||||
if (isEmbedded(v)) return 11;
|
||||
/* fall through */
|
||||
default:
|
||||
throw new Error("Invalid Value<V> in typeCode");
|
||||
}
|
||||
}
|
||||
|
||||
export function compare<V>(
|
||||
a: Value<V>,
|
||||
b: Value<V>,
|
||||
compare_embedded: (a: V, b: V) => number = (a, b) => is(a, b) ? 0 : a < b ? -1 : 1,
|
||||
): number {
|
||||
function cmp(a: Value<V>, b: Value<V>): number {
|
||||
if (isAnnotated<V>(a)) a = a.item;
|
||||
if (isAnnotated<V>(b)) b = b.item;
|
||||
const ta = typeCode(a);
|
||||
const tb = typeCode(b);
|
||||
if (ta < tb) return -1;
|
||||
if (ta > tb) return 1;
|
||||
switch (ta) {
|
||||
case 0:
|
||||
case 3:
|
||||
case 4: {
|
||||
const va = a as any;
|
||||
const vb = b as any;
|
||||
return va < vb ? -1 : va > vb ? 1 : 0;
|
||||
}
|
||||
case 1:
|
||||
case 2: {
|
||||
const va = (a as Float).value;
|
||||
const vb = (b as Float).value;
|
||||
return va < vb ? -1 : va > vb ? 1 : 0;
|
||||
}
|
||||
case 5:
|
||||
return Bytes.compare(a as Bytes, b as Bytes);
|
||||
case 6: {
|
||||
const va = (a as symbol).description!;
|
||||
const vb = (b as symbol).description!;
|
||||
return va < vb ? -1 : va > vb ? 1 : 0;
|
||||
}
|
||||
case 7: {
|
||||
const lr = cmp((a as Record<Value<V>, Value<V>[], V>).label,
|
||||
(b as Record<Value<V>, Value<V>[], V>).label);
|
||||
if (lr !== 0) return lr;
|
||||
/* fall through */
|
||||
}
|
||||
case 8: {
|
||||
const va = a as Value<V>[];
|
||||
const vb = b as Value<V>[];
|
||||
const l = Math.min(va.length, vb.length)
|
||||
for (let i = 0; i < l; i++) {
|
||||
const c = cmp(va[i], vb[i]);
|
||||
if (c !== 0) return c;
|
||||
}
|
||||
return va.length < vb.length ? -1 : va.length > vb.length ? 1 : 0;
|
||||
}
|
||||
case 9: {
|
||||
const va = Array.from(a as Set<V>).sort(cmp);
|
||||
const vb = Array.from(b as Set<V>).sort(cmp);
|
||||
return cmp(va, vb);
|
||||
}
|
||||
case 10: {
|
||||
const va = Array.from(a as Dictionary<V>).sort(cmp);
|
||||
const vb = Array.from(b as Dictionary<V>).sort(cmp);
|
||||
return cmp(va, vb);
|
||||
}
|
||||
case 11:
|
||||
return compare_embedded((a as Embedded<V>).embeddedValue,
|
||||
(b as Embedded<V>).embeddedValue);
|
||||
default:
|
||||
throw new Error("Invalid typeCode: " + ta);
|
||||
}
|
||||
}
|
||||
return cmp(a, b);
|
||||
}
|
|
@ -14,6 +14,7 @@ export * from './fold';
|
|||
export * from './fromjs';
|
||||
export * from './is';
|
||||
export * from './merge';
|
||||
export * from './order';
|
||||
export * from './reader';
|
||||
export * from './record';
|
||||
export * from './strip';
|
||||
|
|
Loading…
Reference in New Issue