Skip to content
Snippets Groups Projects
Commit a0ee98a7 authored by David Sehnal's avatar David Sehnal
Browse files

collections

parent 70cfd4d2
No related branches found
No related tags found
No related merge requests found
// TODO
\ No newline at end of file
/**
* Copyright (c) 2017 molio contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import Iterator from './iterator'
/** An immutable ordered set. */
interface OrderedSet {
readonly size: number,
has(x: number): boolean,
indexOf(x: number): number,
elementAt(i: number): number,
elements(): Iterator<number>
}
interface Impl extends OrderedSet {
readonly min: number,
readonly max: number
}
class RangeImpl implements Impl {
size: number;
has(x: number) { return x >= this.min && x <= this.max; }
indexOf(x: number) { return x >= this.min && x <= this.max ? x - this.min : -1; }
toArray() {
const ret = new Array(this.size);
for (let i = 0; i < this.size; i++) ret[i] = i + this.min;
return ret;
}
elementAt(i: number) { return this.min + i; }
elements() { return Iterator.Range(this.min, this.max); }
constructor(public min: number, public max: number) {
this.size = max - min + 1;
}
}
class ArrayImpl implements Impl {
size: number;
public min: number;
public max: number;
has(x: number) { return x >= this.min && x <= this.max && binarySearch(this.values, x) >= 0; }
indexOf(x: number) { return x >= this.min && x <= this.max ? binarySearch(this.values, x) : -1; }
elementAt(i: number) { return this.values[i]; }
elements() { return Iterator.Array(this.values); }
constructor(public values: ArrayLike<number>) {
this.min = values[0];
this.max = values[values.length - 1];
this.size = values.length;
}
}
namespace OrderedSet {
export function isEmpty(a: OrderedSet) { return a.size === 0; }
export function hashCode(a: OrderedSet) {
// hash of tuple (size, min, max, mid)
const { size } = a;
let hash = 23;
if (!size) return hash;
hash = 31 * hash + size;
hash = 31 * hash + a.elementAt(0);
hash = 31 * hash + a.elementAt(size - 1);
if (size > 2) hash = 31 * hash + a.elementAt(size >> 1);
return hash;
}
// TODO: possibly add more hash functions to allow for multilevel hashing.
export function areEqual(a: OrderedSet, b: OrderedSet) {
if (a === b) return true;
if (a instanceof RangeImpl) {
if (b instanceof RangeImpl) return a.min === b.min && a.max === b.max;
return equalAR(b as ArrayImpl, a);
} else if (b instanceof RangeImpl) {
return equalAR(a as ArrayImpl, b);
}
return equalAA(a as ArrayImpl, b as ArrayImpl);
}
export function areIntersecting(a: OrderedSet, b: OrderedSet) {
if (a === b) return true;
if (!areRangesIntersecting(a, b)) return false;
// if at least one is "range", they must now intersect
if (a instanceof RangeImpl || b instanceof RangeImpl) return true;
return areIntersectingAA((a as ArrayImpl).values, (b as ArrayImpl).values);
}
/** Check if the 2nd argument is a subset of the 1st */
export function isSubset(a: OrderedSet, toTest: OrderedSet) {
if (a === toTest) return true;
if (!isRangeSubset(a, toTest)) return false;
if (!toTest.size || a instanceof RangeImpl) return true;
if (toTest instanceof RangeImpl) return a.indexOf(max(toTest)) - a.indexOf(min(toTest)) + 1 === toTest.size;
return isSubsetAA((a as ArrayImpl).values, (toTest as ArrayImpl).values);
}
export function union(a: OrderedSet, b: OrderedSet) {
if (a instanceof RangeImpl) {
if (b instanceof RangeImpl) return unionRR(a, b);
return unionAR(b as ArrayImpl, a);
} else if (b instanceof RangeImpl) {
return unionAR(a as ArrayImpl, b);
} else return unionAA((a as ArrayImpl).values, (b as ArrayImpl).values);
}
export function intersect(a: OrderedSet, b: OrderedSet) {
if (a instanceof RangeImpl) {
if (b instanceof RangeImpl) return intersectRR(a, b);
return intersectAR(b as ArrayImpl, a);
} else if (b instanceof RangeImpl) {
return intersectAR(a as ArrayImpl, b);
} else {
if (!areRangesIntersecting(a, b)) return Empty;
return intersectAA((a as ArrayImpl).values, (b as ArrayImpl).values);
}
}
export function ofSingleton(value: number): OrderedSet { return new RangeImpl(value, value); }
export function ofRange(min: number, max: number): OrderedSet { return max < min ? Empty : new RangeImpl(min, max); }
/** It is the responsibility of the caller to ensure the array is sorted and contains unique values. */
export function ofSortedArray(xs: ArrayLike<number>): OrderedSet {
if (!xs.length) return Empty;
// check if the array is just a range
if (xs[xs.length - 1] - xs[0] + 1 === xs.length) return ofRange(xs[0], xs[xs.length - 1]);
return new ArrayImpl(xs);
}
export const Empty = new RangeImpl(0, -1);
}
function min(a: OrderedSet) { return (a as Impl).min; }
function max(a: OrderedSet) { return (a as Impl).max; }
function binarySearch(xs: ArrayLike<number>, value: number) {
let min = 0, max = xs.length - 1;
while (min <= max) {
if (min + 11 > max) {
for (let i = min; i <= max; i++) {
if (value === xs[i]) return i;
}
return -1;
}
const mid = (min + max) >> 1;
const v = xs[mid];
if (value < v) max = mid - 1;
else if (value > v) min = mid + 1;
else return mid;
}
return -1;
}
function equalAR(a: ArrayImpl, b: RangeImpl) {
return a.size === b.size && a.min === b.min && a.max === b.max;
}
function equalAA(a: ArrayImpl, b: ArrayImpl) {
if (a.size !== b.size || a.min !== b.min || a.max !== b.max) return false;
const { size, values: xs } = a;
const { values: ys } = b;
for (let i = 0; i < size; i++) {
if (xs[i] !== ys[i]) return false;
}
return true;
}
function areIntersectingAA(xs: ArrayLike<number>, ys: ArrayLike<number>) {
const la = xs.length, lb = ys.length;
let i = 0, j = 0;
while (i < la && j < lb) {
const x = xs[i], y = ys[j];
if (x < y) { i++; }
else if (x > y) { j++; }
else return true;
}
return false;
}
function isSubsetAA(xs: ArrayLike<number>, ys: ArrayLike<number>) {
const la = xs.length, lb = ys.length;
let i = 0, j = 0, equal = 0;
while (i < la && j < lb) {
const x = xs[i], y = ys[j];
if (x < y) { i++; }
else if (x > y) { j++; }
else { i++; j++; equal++; }
}
return equal === lb;
}
function areRangesIntersecting(a: OrderedSet, b: OrderedSet) {
return a.size > 0 && b.size > 0 && max(a) >= min(b) && min(a) <= max(b);
}
function isRangeSubset(a: OrderedSet, b: OrderedSet) {
if (!a.size) return b.size === 0;
if (!b.size) return true;
return min(a) <= min(b) && max(a) >= max(b);
}
function unionRR(a: RangeImpl, b: RangeImpl) {
if (!a.size) return b;
if (!b.size) return a;
if (areRangesIntersecting(a, b)) return OrderedSet.ofRange(Math.min(a.min, b.min), Math.max(a.max, b.max));
let l, r;
if (a.min < b.min) { l = a; r = b; }
else { l = b; r = a; }
const arr = new Int32Array(a.size + b.size);
for (let i = 0; i < l.size; i++) arr[i] = i + l.min;
for (let i = 0; i < r.size; i++) arr[i + l.size] = i + r.min;
return OrderedSet.ofSortedArray(arr);
}
function unionAR(a: ArrayImpl, b: RangeImpl) {
if (!b.size) return a;
// is the array fully contained in the range?
if (a.min >= b.min && a.max <= b.max) return b;
const xs = a.values;
const { min, max } = b;
let start = 0, end = xs.length - 1;
while (xs[start] < min) { start++; }
while (xs[end] > max) { end--; }
end++;
const size = start + (xs.length - end) + b.size;
const indices = new Int32Array(size);
let offset = 0;
for (let i = 0; i < start; i++) indices[offset++] = xs[i];
for (let i = min; i <= max; i++) indices[offset++] = i;
for (let i = end, _i = xs.length; i < _i; i++) indices[offset] = xs[i];
return OrderedSet.ofSortedArray(indices);
}
function unionAA(xs: ArrayLike<number>, ys: ArrayLike<number>) {
const la = xs.length, lb = ys.length;
// sorted list merge.
let i = 0, j = 0, resultSize = 0;
while (i < la && j < lb) {
const x = xs[i], y = ys[j];
resultSize++;
if (x < y) { i++; }
else if (x > y) { j++; }
else { i++; j++; }
}
resultSize += Math.max(la - i, lb - j);
const indices = new Int32Array(resultSize);
let offset = 0;
i = 0;
j = 0;
while (i < la && j < lb) {
const x = xs[i], y = ys[j];
if (x < y) { indices[offset++] = x; i++; }
else if (x > y) { indices[offset++] = y; j++; }
else { indices[offset++] = x; i++; j++; }
}
for (; i < la; i++) { indices[offset++] = xs[i]; }
for (; j < lb; j++) { indices[offset++] = ys[j]; }
return OrderedSet.ofSortedArray(indices);
}
function intersectRR(a: RangeImpl, b: RangeImpl) {
if (!areRangesIntersecting(a, b)) return OrderedSet.Empty;
return OrderedSet.ofRange(Math.max(a.min, b.min), Math.min(a.max, b.max));
}
function intersectAR(a: ArrayImpl, r: RangeImpl) {
const xs = a.values;
let resultSize = 0;
for (let i = 0, _i = xs.length; i < _i; i++) {
if (r.has(xs[i])) resultSize++;
}
if (!resultSize) return OrderedSet.Empty;
const indices = new Int32Array(resultSize);
let offset = 0;
for (let i = 0, _i = xs.length; i < _i; i++) {
if (r.has(xs[i])) indices[offset++] = xs[i];
}
return OrderedSet.ofSortedArray(indices);
}
function intersectAA(xs: ArrayLike<number>, ys: ArrayLike<number>) {
const la = xs.length, lb = ys.length;
// a variation on sorted list merge.
let i = 0, j = 0, resultSize = 0;
while (i < la && j < lb) {
const x = xs[i], y = ys[j];
if (x < y) { i++; }
else if (x > y) { j++; }
else { i++; j++; resultSize++; }
}
if (!resultSize) return OrderedSet.Empty;
const indices = new Int32Array(resultSize);
let offset = 0;
i = 0;
j = 0;
while (i < la && j < lb) {
const x = xs[i], y = ys[j];
if (x < y) { i++; }
else if (x > y) { j++; }
else { indices[offset++] = x; i++; j++; }
}
return OrderedSet.ofSortedArray(indices);
}
export default OrderedSet
\ No newline at end of file
/**
* Copyright (c) 2017 molio contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import Iterator from './iterator'
interface RangeSet {
readonly size: number,
has(x: number): boolean,
indexOf(x: number): number,
elementAt(i: number): number,
elements(): Iterator<number>
}
namespace RangeSet {
interface Impl extends RangeSet {
readonly min: number,
readonly max: number,
toArray(): ArrayLike<number>
}
export function hashCode(a: RangeSet) {
// hash of tuple (size, min, max, mid)
const { size } = a;
let hash = 23;
if (!size) return hash;
hash = 31 * hash + size;
hash = 31 * hash + a.elementAt(0);
hash = 31 * hash + a.elementAt(size - 1);
if (size > 2) hash = 31 * hash + a.elementAt(size >> 1);
return hash;
}
// TODO: possibly add more hash functions to allow for multilevel hashing.
export function areEqual(a: RangeSet, b: RangeSet) {
if (a === b) return true;
if (a instanceof RangeImpl) {
if (b instanceof RangeImpl) return a.min === b.min && a.max === b.max;
return equalAR(b as ArrayImpl, a);
} else if (b instanceof RangeImpl) {
return equalAR(a as ArrayImpl, b);
}
return equalAA(a as ArrayImpl, b as ArrayImpl);
}
export function union(a: RangeSet, b: RangeSet) {
if (a instanceof RangeImpl) {
if (b instanceof RangeImpl) return unionRR(a, b);
return unionAR(b as ArrayImpl, a);
} else if (b instanceof RangeImpl) {
return unionAR(a as ArrayImpl, b);
} else return unionAA((a as Impl).toArray(), (b as Impl).toArray());
}
export function intersect(a: RangeSet, b: RangeSet) {
if (a instanceof RangeImpl) {
if (b instanceof RangeImpl) return intersectRR(a, b);
return intersectAR(b as ArrayImpl, a);
} else if (b instanceof RangeImpl) {
return intersectAR(a as ArrayImpl, b);
} else {
const ai = a as Impl, bi = b as Impl;
if (!areRangesIntersecting(ai, bi)) return Empty;
return intersectAA(ai.toArray(), bi.toArray());
}
}
class RangeImpl implements Impl {
size: number;
has(x: number) { return x >= this.min && x <= this.max; }
indexOf(x: number) { return x >= this.min && x <= this.max ? x - this.min : -1; }
toArray() {
const ret = new Array(this.size);
for (let i = 0; i < this.size; i++) ret[i] = i + this.min;
return ret;
}
elementAt(i: number) { return this.min + i; }
elements() { return Iterator.Range(this.min, this.max); }
constructor(public min: number, public max: number) {
this.size = max - min + 1;
}
}
class ArrayImpl implements Impl {
size: number;
public min: number;
public max: number;
has(x: number) { return x >= this.min && x <= this.max && binarySearch(this.values, x) >= 0; }
indexOf(x: number) { return x >= this.min && x <= this.max ? binarySearch(this.values, x) : -1; }
toArray() { return this.values; }
elementAt(i: number) { return this.values[i]; }
elements() { return Iterator.Array(this.values); }
constructor(public values: ArrayLike<number>) {
this.min = values[0];
this.max = values[values.length - 1];
this.size = values.length;
}
}
export function ofSingleton(value: number): RangeSet { return new RangeImpl(value, value); }
export function ofRange(min: number, max: number): RangeSet { return new RangeImpl(min, max); }
/** It is the responsibility of the caller to ensure the array is sorted and contains unique values. */
export function ofSortedArray(xs: ArrayLike<number>): RangeSet {
if (!xs.length) return Empty;
// check if the array is just a range
if (xs[xs.length - 1] - xs[0] + 1 === xs.length) return ofRange(xs[0], xs[xs.length - 1]);
return new ArrayImpl(xs);
}
export const Empty = ofRange(0, -1);
function binarySearch(xs: ArrayLike<number>, value: number) {
let min = 0, max = xs.length - 1;
while (min <= max) {
if (min + 11 > max) {
for (let i = min; i <= max; i++) {
if (value === xs[i]) return i;
}
return -1;
}
const mid = (min + max) >> 1;
const v = xs[mid];
if (value < v) max = mid - 1;
else if (value > v) min = mid + 1;
else return mid;
}
return -1;
}
function equalAR(a: ArrayImpl, b: RangeImpl) {
return a.size === b.size && a.min === b.min && a.max === b.max;
}
function equalAA(a: ArrayImpl, b: ArrayImpl) {
if (a.size !== b.size || a.min !== b.min || a.max !== b.max) return false;
const { size, values: xs } = a;
const { values: ys } = b;
for (let i = 0; i < size; i++) {
if (xs[i] !== ys[i]) return false;
}
return true;
}
function areRangesIntersecting(a: Impl, b: Impl) {
return a.size > 0 && b.size > 0 && a.max >= b.min && a.min <= b.max;
}
function unionRR(a: RangeImpl, b: RangeImpl) {
if (!a.size) return b;
if (!b.size) return a;
if (areRangesIntersecting(a, b)) return ofRange(Math.min(a.min, b.min), Math.max(a.max, b.max));
let l, r;
if (a.min < b.min) { l = a; r = b; }
else { l = b; r = a; }
const arr = new Int32Array(a.size + b.size);
for (let i = 0; i < l.size; i++) arr[i] = i + l.min;
for (let i = 0; i < r.size; i++) arr[i + l.size] = i + r.min;
return ofSortedArray(arr);
}
function unionAR(a: ArrayImpl, b: RangeImpl) {
if (!b.size) return a;
// is the array fully contained in the range?
if (a.min >= b.min && a.max <= b.max) return b;
const xs = a.values;
const { min, max } = b;
let start = 0, end = xs.length - 1;
while (xs[start] < min) { start++; }
while (xs[end] > max) { end--; }
end++;
const size = start + (xs.length - end) + b.size;
const indices = new Int32Array(size);
let offset = 0;
for (let i = 0; i < start; i++) indices[offset++] = xs[i];
for (let i = min; i <= max; i++) indices[offset++] = i;
for (let i = end, _i = xs.length; i < _i; i++) indices[offset] = xs[i];
return ofSortedArray(indices);
}
function unionAA(xs: ArrayLike<number>, ys: ArrayLike<number>) {
const la = xs.length, lb = ys.length;
// sorted list merge.
let i = 0, j = 0, resultSize = 0;
while (i < la && j < lb) {
const x = xs[i], y = ys[j];
resultSize++;
if (x < y) { i++; }
else if (x > y) { j++; }
else { i++; j++; }
}
resultSize += Math.max(la - i, lb - j);
const indices = new Int32Array(resultSize);
let offset = 0;
i = 0;
j = 0;
while (i < la && j < lb) {
const x = xs[i], y = ys[j];
if (x < y) { indices[offset++] = x; i++; }
else if (x > y) { indices[offset++] = y; j++; }
else { indices[offset++] = x; i++; j++; }
}
for (; i < la; i++) { indices[offset++] = xs[i]; }
for (; j < lb; j++) { indices[offset++] = ys[j]; }
return ofSortedArray(indices);
}
function intersectRR(a: RangeImpl, b: RangeImpl) {
if (!areRangesIntersecting(a, b)) return Empty;
return ofRange(Math.max(a.min, b.min), Math.min(a.max, b.max));
}
function intersectAR(a: ArrayImpl, r: RangeImpl) {
const xs = a.values;
let resultSize = 0;
for (let i = 0, _i = xs.length; i < _i; i++) {
if (r.has(xs[i])) resultSize++;
}
if (!resultSize) return Empty;
const indices = new Int32Array(resultSize);
let offset = 0;
for (let i = 0, _i = xs.length; i < _i; i++) {
if (r.has(xs[i])) indices[offset++] = xs[i];
}
return ofSortedArray(indices);
}
function intersectAA(xs: ArrayLike<number>, ys: ArrayLike<number>) {
const la = xs.length, lb = ys.length;
// a variation on sorted list merge.
let i = 0, j = 0, resultSize = 0;
while (i < la && j < lb) {
const x = xs[i], y = ys[j];
if (x < y) { i++; }
else if (x > y) { j++; }
else { i++; j++; resultSize++; }
}
if (!resultSize) return Empty;
const indices = new Int32Array(resultSize);
let offset = 0;
i = 0;
j = 0;
while (i < la && j < lb) {
const x = xs[i], y = ys[j];
if (x < y) { i++; }
else if (x > y) { j++; }
else { indices[offset++] = x; i++; j++; }
}
return ofSortedArray(indices);
}
}
export default RangeSet
\ No newline at end of file
......@@ -7,7 +7,7 @@
import Iterator from '../collections/iterator'
import IntPair from '../collections/int-pair'
import * as Sort from '../collections/sort'
import RangeSet from '../collections/range-set'
import OrderedSet from '../collections/ordered-set'
import LinkedIndex from '../collections/linked-index'
describe('basic iterators', () => {
......@@ -121,71 +121,101 @@ describe('qsort-dual array', () => {
})
describe('range set', () => {
function testEq(name: string, set: RangeSet, expected: number[]) {
function testEq(name: string, set: OrderedSet, expected: number[]) {
it(name, () => {
// copy the arrays to ensure "compatibility" between typed and native arrays
expect(Array.prototype.slice.call(Iterator.toArray(set.elements()))).toEqual(Array.prototype.slice.call(expected));
});
}
const empty = RangeSet.Empty;
const singleton = RangeSet.ofSingleton(10);
const range = RangeSet.ofRange(1, 4);
const arr = RangeSet.ofSortedArray([1, 3, 6]);
const empty = OrderedSet.Empty;
const singleton = OrderedSet.ofSingleton(10);
const range = OrderedSet.ofRange(1, 4);
const arr = OrderedSet.ofSortedArray([1, 3, 6]);
testEq('empty', empty, []);
testEq('singleton', singleton, [10]);
testEq('range', range, [1, 2, 3, 4]);
testEq('sorted array', arr, [1, 3, 6]);
expect(RangeSet.areEqual(empty, singleton)).toBe(false);
expect(RangeSet.areEqual(singleton, singleton)).toBe(true);
expect(RangeSet.areEqual(range, singleton)).toBe(false);
expect(RangeSet.areEqual(arr, RangeSet.ofSortedArray([1, 3, 6]))).toBe(true);
expect(RangeSet.areEqual(arr, RangeSet.ofSortedArray([1, 4, 6]))).toBe(false);
expect(empty.has(10)).toBe(false);
expect(empty.indexOf(10)).toBe(-1);
expect(singleton.has(10)).toBe(true);
expect(singleton.has(11)).toBe(false);
expect(singleton.indexOf(10)).toBe(0);
expect(singleton.indexOf(11)).toBe(-1);
expect(range.has(4)).toBe(true);
expect(range.has(5)).toBe(false);
expect(range.indexOf(4)).toBe(3);
expect(range.indexOf(11)).toBe(-1);
expect(arr.has(3)).toBe(true);
expect(arr.has(4)).toBe(false);
expect(arr.indexOf(3)).toBe(1);
expect(arr.indexOf(11)).toBe(-1);
testEq('union ES', RangeSet.union(empty, singleton), [10]);
testEq('union ER', RangeSet.union(empty, range), [1, 2, 3, 4]);
testEq('union EA', RangeSet.union(empty, arr), [1, 3, 6]);
testEq('union SS', RangeSet.union(singleton, RangeSet.ofSingleton(16)), [10, 16]);
testEq('union SR', RangeSet.union(range, singleton), [1, 2, 3, 4, 10]);
testEq('union SA', RangeSet.union(arr, singleton), [1, 3, 6, 10]);
testEq('union SA1', RangeSet.union(arr, RangeSet.ofSingleton(3)), [1, 3, 6]);
testEq('union RR', RangeSet.union(range, range), [1, 2, 3, 4]);
testEq('union RR1', RangeSet.union(range, RangeSet.ofRange(6, 7)), [1, 2, 3, 4, 6, 7]);
testEq('union RR2', RangeSet.union(range, RangeSet.ofRange(3, 5)), [1, 2, 3, 4, 5]);
testEq('union RA', RangeSet.union(range, arr), [1, 2, 3, 4, 6]);
testEq('union AA', RangeSet.union(arr, RangeSet.ofSortedArray([2, 4, 6, 7])), [1, 2, 3, 4, 6, 7]);
testEq('union AA1', RangeSet.union(arr, RangeSet.ofSortedArray([2, 3, 4, 6, 7])), [1, 2, 3, 4, 6, 7]);
testEq('intersect ES', RangeSet.intersect(empty, singleton), []);
testEq('intersect ER', RangeSet.intersect(empty, range), []);
testEq('intersect EA', RangeSet.intersect(empty, arr), []);
testEq('intersect SS', RangeSet.intersect(singleton, RangeSet.ofSingleton(16)), []);
testEq('intersect SS', RangeSet.intersect(singleton, singleton), [10]);
testEq('intersect SR', RangeSet.intersect(range, singleton), []);
testEq('intersect RR', RangeSet.intersect(range, range), [1, 2, 3, 4]);
testEq('intersect RR2', RangeSet.intersect(range, RangeSet.ofRange(3, 5)), [3, 4]);
testEq('intersect RA', RangeSet.intersect(range, arr), [1, 3]);
testEq('intersect AA', RangeSet.intersect(arr, RangeSet.ofSortedArray([2, 3, 4, 6, 7])), [3, 6]);
it('equality', () => {
expect(OrderedSet.areEqual(empty, singleton)).toBe(false);
expect(OrderedSet.areEqual(singleton, singleton)).toBe(true);
expect(OrderedSet.areEqual(range, singleton)).toBe(false);
expect(OrderedSet.areEqual(arr, OrderedSet.ofSortedArray([1, 3, 6]))).toBe(true);
expect(OrderedSet.areEqual(arr, OrderedSet.ofSortedArray([1, 4, 6]))).toBe(false);
});
it('areIntersecting', () => {
expect(OrderedSet.areIntersecting(range, arr)).toBe(true);
expect(OrderedSet.areIntersecting(empty, empty)).toBe(true);
expect(OrderedSet.areIntersecting(empty, singleton)).toBe(false);
expect(OrderedSet.areIntersecting(empty, range)).toBe(false);
expect(OrderedSet.areIntersecting(empty, arr)).toBe(false);
});
it('isSubset', () => {
expect(OrderedSet.isSubset(singleton, empty)).toBe(true);
expect(OrderedSet.isSubset(range, empty)).toBe(true);
expect(OrderedSet.isSubset(arr, empty)).toBe(true);
expect(OrderedSet.isSubset(empty, empty)).toBe(true);
expect(OrderedSet.isSubset(empty, singleton)).toBe(false);
expect(OrderedSet.isSubset(empty, range)).toBe(false);
expect(OrderedSet.isSubset(empty, arr)).toBe(false);
expect(OrderedSet.isSubset(singleton, range)).toBe(false);
expect(OrderedSet.isSubset(range, OrderedSet.ofRange(2, 3))).toBe(true);
expect(OrderedSet.isSubset(arr, range)).toBe(false);
expect(OrderedSet.isSubset(arr, arr)).toBe(true);
expect(OrderedSet.isSubset(arr, OrderedSet.ofSortedArray([1, 3]))).toBe(true);
expect(OrderedSet.isSubset(arr, OrderedSet.ofSortedArray([1, 3, 7]))).toBe(false);
expect(OrderedSet.isSubset(arr, OrderedSet.ofSortedArray([1, 3, 10, 45]))).toBe(false);
});
it('access/membership', () => {
expect(empty.has(10)).toBe(false);
expect(empty.indexOf(10)).toBe(-1);
expect(singleton.has(10)).toBe(true);
expect(singleton.has(11)).toBe(false);
expect(singleton.indexOf(10)).toBe(0);
expect(singleton.indexOf(11)).toBe(-1);
expect(range.has(4)).toBe(true);
expect(range.has(5)).toBe(false);
expect(range.indexOf(4)).toBe(3);
expect(range.indexOf(11)).toBe(-1);
expect(arr.has(3)).toBe(true);
expect(arr.has(4)).toBe(false);
expect(arr.indexOf(3)).toBe(1);
expect(arr.indexOf(11)).toBe(-1);
});
testEq('union ES', OrderedSet.union(empty, singleton), [10]);
testEq('union ER', OrderedSet.union(empty, range), [1, 2, 3, 4]);
testEq('union EA', OrderedSet.union(empty, arr), [1, 3, 6]);
testEq('union SS', OrderedSet.union(singleton, OrderedSet.ofSingleton(16)), [10, 16]);
testEq('union SR', OrderedSet.union(range, singleton), [1, 2, 3, 4, 10]);
testEq('union SA', OrderedSet.union(arr, singleton), [1, 3, 6, 10]);
testEq('union SA1', OrderedSet.union(arr, OrderedSet.ofSingleton(3)), [1, 3, 6]);
testEq('union RR', OrderedSet.union(range, range), [1, 2, 3, 4]);
testEq('union RR1', OrderedSet.union(range, OrderedSet.ofRange(6, 7)), [1, 2, 3, 4, 6, 7]);
testEq('union RR2', OrderedSet.union(range, OrderedSet.ofRange(3, 5)), [1, 2, 3, 4, 5]);
testEq('union RA', OrderedSet.union(range, arr), [1, 2, 3, 4, 6]);
testEq('union AA', OrderedSet.union(arr, OrderedSet.ofSortedArray([2, 4, 6, 7])), [1, 2, 3, 4, 6, 7]);
testEq('union AA1', OrderedSet.union(arr, OrderedSet.ofSortedArray([2, 3, 4, 6, 7])), [1, 2, 3, 4, 6, 7]);
testEq('intersect ES', OrderedSet.intersect(empty, singleton), []);
testEq('intersect ER', OrderedSet.intersect(empty, range), []);
testEq('intersect EA', OrderedSet.intersect(empty, arr), []);
testEq('intersect SS', OrderedSet.intersect(singleton, OrderedSet.ofSingleton(16)), []);
testEq('intersect SS', OrderedSet.intersect(singleton, singleton), [10]);
testEq('intersect SR', OrderedSet.intersect(range, singleton), []);
testEq('intersect RR', OrderedSet.intersect(range, range), [1, 2, 3, 4]);
testEq('intersect RR2', OrderedSet.intersect(range, OrderedSet.ofRange(3, 5)), [3, 4]);
testEq('intersect RA', OrderedSet.intersect(range, arr), [1, 3]);
testEq('intersect AA', OrderedSet.intersect(arr, OrderedSet.ofSortedArray([2, 3, 4, 6, 7])), [3, 6]);
});
describe('linked-index', () => {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment