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

sets (temp)

parent 66072249
No related branches found
No related tags found
No related merge requests found
import * as B from 'benchmark'
import OrderedSet from '../structure/collections/ordered-set'
import IntPair from '../structure/collections/int-pair'
const range = OrderedSet.ofRange(0, 100);
const pairSet = IntPair.pack1(0, 100);
namespace PairSet {
const pair = IntPair.zero();
export function has(p: number, x: number) {
IntPair.unpack(p, pair);
return x >= pair.fst && x <= pair.snd;
}
}
const suite = new B.Suite();
const values: number[] = [];
for (let i = 0; i < 1000000; i++) values[i] = (Math.random() * 1000) | 0;
let idx = 0;
suite
.add('range', () => range.has(idx % values.length))
.add('pair', () => PairSet.has(pairSet, idx % values.length))
.on('cycle', (e: any) => {
console.log(String(e.target));
})
// .run();
console.log(IntPair.pack1(0, -20));
console.log(IntPair.unpack1(IntPair.pack1(0, -20)));
...@@ -60,6 +60,12 @@ namespace IntPair { ...@@ -60,6 +60,12 @@ namespace IntPair {
return _int32[1]; return _int32[1];
} }
export function areEqual(a: number, b: number) {
_float64[0] = a;
_float64_1[0] = b;
return _int32[0] === _int32_1[0] && _int32[1] === _int32_1[1];
}
export function compare(a: number, b: number) { export function compare(a: number, b: number) {
_float64[0] = a; _float64[0] = a;
_float64_1[0] = b; _float64_1[0] = b;
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* @author David Sehnal <david.sehnal@gmail.com> * @author David Sehnal <david.sehnal@gmail.com>
*/ */
import OrderedSet from './ordered-set' import OrderedSet from './ordered-set.1'
import Iterator from './iterator' import Iterator from './iterator'
import IntPair from './int-pair' import IntPair from './int-pair'
import { sortArray } from './sort' import { sortArray } from './sort'
...@@ -101,8 +101,11 @@ namespace MultiSet { ...@@ -101,8 +101,11 @@ namespace MultiSet {
class ElementsIterator implements Iterator<IntPair> { class ElementsIterator implements Iterator<IntPair> {
private pair = IntPair.zero(); private pair = IntPair.zero();
private unit = 0; private unit = 0;
private currentIndex = -1;
private currentIterator: Iterator<number> = Iterator.Empty; private setIndex = -1;
private currentIndex = 0;
private currentSize = 0;
private currentSet: OrderedSet = OrderedSet.Empty;
[Symbol.iterator]() { return new ElementsIterator(this.elements); }; [Symbol.iterator]() { return new ElementsIterator(this.elements); };
done: boolean; done: boolean;
...@@ -111,31 +114,32 @@ namespace MultiSet { ...@@ -111,31 +114,32 @@ namespace MultiSet {
move() { move() {
if (this.done) return this.pair; if (this.done) return this.pair;
let next = this.currentIterator.move(); if (this.currentIndex >= this.currentSize) {
if (this.currentIterator.done) { if (!this.advance()) return this.pair;
if (!this.advanceIterator()) {
this.done = true;
return this.pair;
}
next = this.currentIterator.move();
} }
const next = OrderedSet.elementAt(this.currentSet, this.currentIndex++);
this.pair.snd = next; this.pair.snd = next;
return this.pair; return this.pair;
} }
private advanceIterator() { private advance() {
const keys = this.elements.keys; const keys = this.elements.keys;
if (++this.currentIndex >= keys.size) return false; if (++this.setIndex >= keys.size) {
this.unit = keys.elementAt(this.currentIndex); this.done = true;
return false;
}
this.unit = OrderedSet.elementAt(keys, this.setIndex);
this.pair.fst = this.unit; this.pair.fst = this.unit;
this.currentIterator = this.elements[this.unit].elements(); this.currentSet = this.elements[this.unit];
this.currentIndex = 0;
this.currentSize = this.currentSet.size;
return true; return true;
} }
constructor(private elements: MultiSetElements) { constructor(private elements: MultiSetElements) {
this.done = elements.keys.size === 0; this.done = elements.keys.size === 0;
this.advanceIterator(); this.advance();
} }
} }
......
/**
* Copyright (c) 2017 molio contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import IntPair from './int-pair'
import { hash3, hash4 } from './hash-functions'
type Nums = ArrayLike<number>
type OrderedSet = number | Nums
/** An immutable ordered set. */
namespace OrderedSet {
export function ofSingleton(value: number): OrderedSet { return IntPair.pack1(value, value); }
export function ofRange(min: number, max: number): OrderedSet { return max < min ? Empty : IntPair.pack1(min, max); }
/** It is the responsibility of the caller to ensure the array is sorted and contains unique values. */
export function ofSortedArray(xs: Nums): 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 xs;
}
export const Empty: OrderedSet = IntPair.pack1(0, -1);
export function size(set: OrderedSet) { return typeof set === 'number' ? sizeR(set) : set.length; }
export function has(set: OrderedSet, x: number) { return typeof set === 'number' ? hasR(set, x) : hasA(set, x); }
export function indexOf(set: OrderedSet, x: number) { return typeof set === 'number' ? indexOfR(set, x) : indexOfA(set, x); }
export function elementAt(set: OrderedSet, i: number) { return typeof set === 'number' ? elementAtR(set, i) : set[i]; }
export function min(set: OrderedSet) { return typeof set === 'number' ? minR(set) : set[0]; }
export function max(set: OrderedSet) { return typeof set === 'number' ? maxR(set) : set[set.length - 1]; }
export function hashCode(set: OrderedSet) {
// hash of tuple (size, min, max, mid)
const s = size(set);
if (!s) return 0;
if (s > 2) return hash4(s, elementAt(set, 0), elementAt(set, s - 1), elementAt(set, s >> 1));
return hash3(s, elementAt(set, 0), elementAt(set, s - 1));
}
// TODO: possibly add more hash functions to allow for multilevel hashing.
export function areEqual(a: OrderedSet, b: OrderedSet) {
if (typeof a === 'number') {
if (typeof b === 'number') return equalRR(a, b);
return false;
} else if (typeof b === 'number') return false;
else if (a === b) return true;
return equalAA(a, b);
}
export function areIntersecting(a: OrderedSet, b: OrderedSet) {
// if at least one is "range", they must now intersect
if (typeof a === 'number') {
if (typeof b === 'number') return equalRR(a, b) || areRangesIntersecting(a, b);
return areRangesIntersecting(a, b);
}
if (!areRangesIntersecting(a, b)) return false;
else if (typeof b === 'number') return false;
if (a === b) return true;
return areIntersectingAA(a, b);
}
/** Check if the 2nd argument is a subset of the 1st */
export function isSubset(set: OrderedSet, toTest: OrderedSet) {
if (set === toTest) return true;
if (!isRangeSubset(set, toTest)) return false;
const testSize = size(toTest);
if (typeof set === 'number' || !testSize) return true;
if (typeof toTest === 'number') return indexOf(set, maxR(toTest)) - indexOf(set, minR(toTest)) + 1 === testSize;
return isSubsetAA(set, toTest);
}
export function getInsertionIndex(set: OrderedSet, x: number) {
return typeof set === 'number' ? rangeSearchIndex(set, x) : binarySearchIndex(set, x);
}
export function getIntervalRange(set: OrderedSet, min: number, max: number) {
const { start, end } = getStartEnd(set, min, max);
return { start, end };
}
export function union(a: OrderedSet, b: OrderedSet) {
if (a === b) return a;
if (typeof a === 'number') {
if (typeof b === 'number') return unionRR(a, b);
return unionAR(b, a);
} else if (typeof b === 'number') {
return unionAR(a, b);
} else return unionAA(a, b);
}
export function intersect(a: OrderedSet, b: OrderedSet) {
if (a === b) return a;
if (typeof a === 'number') {
if (typeof b === 'number') return intersectRR(a, b);
return intersectAR(b, a);
} else if (typeof b === 'number') {
return intersectAR(a, b);
} else {
if (!areRangesIntersecting(a, b)) return Empty;
return intersectAA(a, b);
}
}
export function subtract(a: OrderedSet, b: OrderedSet) {
if (a === b) return Empty;
if (!areRangesIntersecting(a, b)) return a;
if (typeof a === 'number') {
if (typeof b === 'number') return substractRR(a, b);
return subtractRA(a, b);
} else if (typeof b === 'number') {
return subtractAR(a, b);
} else {
return subtractAA(a, b);
}
}
}
import S = OrderedSet
const minR = IntPair.fst
const maxR = IntPair.snd
const equalRR = IntPair.areEqual
const _eR = IntPair.zero();
function sizeR(set: number) { IntPair.unpack(set, _eR); return _eR.snd - _eR.fst + 1; }
function hasR(set: number, x: number) { IntPair.unpack(set, _eR); return x >= _eR.fst && x <= _eR.snd; }
function indexOfR(set: number, x: number) { IntPair.unpack(set, _eR); return x >= _eR.fst && x <= _eR.snd ? x - _eR.fst : -1; }
function elementAtR(set: number, i: number) { return IntPair.fst(set) + i; }
function hasA(set: Nums, x: number) { return x >= set[0] && x <= set[set.length - 1] && binarySearch(set, x) >= 0; }
function indexOfA(set: Nums, x: number) { return x >= set[0] && x <= set[set.length - 1] ? binarySearch(set, x) : -1; }
function binarySearch(xs: Nums, 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 binarySearchIndex(xs: Nums, value: number) {
let min = 0, max = xs.length - 1;
while (min < max) {
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;
}
if (min > max) return max + 1;
return xs[min] >= value ? min : min + 1;
}
const _rsiR = IntPair.zero();
function rangeSearchIndex(r: number, value: number) {
IntPair.unpack(r, _rsiR);
if (value < _rsiR.fst) return 0;
if (value > _rsiR.snd) return _rsiR.snd - _rsiR.fst + 1;
return value - _rsiR.fst;
}
const _maxIntRangeRet = { i: 0, j: 0, endA: 0, endB: 0 };
function getMaxIntersectionRange(xs: Nums, ys: Nums) {
const la = xs.length - 1, lb = ys.length - 1;
_maxIntRangeRet.i = binarySearchIndex(xs, ys[0]);
_maxIntRangeRet.j = binarySearchIndex(ys, xs[0]);
_maxIntRangeRet.endA = Math.min(binarySearchIndex(xs, ys[lb]), la);
_maxIntRangeRet.endB = Math.min(binarySearchIndex(ys, xs[la]), lb);
return _maxIntRangeRet;
}
const _startEndRet = { start: 0, end: 0 };
function getStartEnd(set: OrderedSet, min: number, max: number) {
_startEndRet.start = S.getInsertionIndex(set, min);
let end = S.getInsertionIndex(set, max);
if (end < S.size(set) && S.elementAt(set, end) === max) end++;
_startEndRet.end = end;
return _startEndRet;
}
function equalAA(a: Nums, b: Nums) {
let size = a.length;
if (a.length !== b.length || a[0] !== b[0] || a[size - 1] !== b[size - 1]) return false;
for (let i = 0; i < size; i++) {
if (a[i] !== b[i]) return false;
}
return true;
}
function areIntersectingAA(xs: Nums, ys: Nums) {
let { i, j, endA, endB } = getMaxIntersectionRange(xs, ys);
while (i <= endA && j <= endB) {
const x = xs[i], y = ys[j];
if (x < y) { i++; }
else if (x > y) { j++; }
else return true;
}
return false;
}
function isSubsetAA(xs: Nums, ys: Nums) {
const lenB = ys.length;
let { i, j, endA, endB } = getMaxIntersectionRange(xs, ys);
// the 2nd array must be able to advance by at least lenB elements
if (endB - j + 1 < lenB || endA - j + 1 < lenB) return false;
let equal = 0;
while (i <= endA && j <= endB) {
const x = xs[i], y = ys[j];
if (x < y) { i++; }
else if (x > y) { j++; }
else { i++; j++; equal++; }
}
return equal === lenB;
}
function areRangesIntersecting(a: OrderedSet, b: OrderedSet) {
return S.size(a) > 0 && S.size(b) > 0 && S.max(a) >= S.min(b) && S.min(a) <= S.max(b);
}
function isRangeSubset(a: OrderedSet, b: OrderedSet) {
if (!S.size(a)) return S.size(b) === 0;
if (!S.size(b)) return true;
return S.min(a) <= S.min(b) && S.max(a) >= S.max(b);
}
function unionRR(a: number, b: number) {
const sizeA = S.size(a), sizeB = S.size(b);
if (!sizeA) return b;
if (!sizeB) return a;
const minA = minR(a), minB = minR(b);
if (areRangesIntersecting(a, b)) return S.ofRange(Math.min(minA, minB), Math.max(maxR(a), maxR(b)));
let lSize, lMin, rSize, rMin;
if (minR(a) < minR(b)) { lSize = sizeA; lMin = minA; rSize = sizeB; rMin = minB; }
else { lSize = sizeB; lMin = minB; rSize = sizeA; rMin = minA; }
const arr = new Int32Array(sizeA + sizeB);
for (let i = 0; i < lSize; i++) arr[i] = i + lMin;
for (let i = 0; i < rSize; i++) arr[i + lSize] = i + rMin;
return S.ofSortedArray(arr);
}
const _uAR = IntPair.zero();
function unionAR(a: Nums, b: number) {
const bSize = S.size(b);
if (!bSize) return a;
// is the array fully contained in the range?
if (isRangeSubset(b, a)) return b;
IntPair.unpack(b, _uAR);
const min = _uAR.fst, max = _uAR.snd;
const { start, end } = getStartEnd(a, min, max);
const size = start + (a.length - end) + bSize;
const indices = new Int32Array(size);
let offset = 0;
for (let i = 0; i < start; i++) indices[offset++] = a[i];
for (let i = min; i <= max; i++) indices[offset++] = i;
for (let i = end, _i = a.length; i < _i; i++) indices[offset] = a[i];
return OrderedSet.ofSortedArray(indices);
}
function unionAA(a: Nums, b: Nums) {
const lenA = a.length, lenB = b.length;
let { i: sI, j: sJ, endA, endB } = getMaxIntersectionRange(a, b);
let i = sI, j = sJ;
let commonCount = 0;
while (i <= endA && j <= endB) {
const x = a[i], y = b[j];
if (x < y) { i++; }
else if (x > y) { j++; }
else { i++; j++; commonCount++; }
}
if (!commonCount) return a;
if (commonCount >= lenA) return OrderedSet.Empty
const resultSize = lenA + lenB - commonCount;
const l = Math.min(a[0], b[0]), r = Math.max(a[lenA - 1], b[lenB - 1]);
// is this just a range?
if (resultSize === r - l + 1) {
return OrderedSet.ofRange(l, r);
}
const indices = new Int32Array(lenA + lenB - commonCount);
let offset = 0;
// insert the "prefixes"
for (let k = 0; k < sI; k++) indices[offset++] = a[k];
for (let k = 0; k < sJ; k++) indices[offset++] = a[k];
// insert the common part
i = sI;
j = sJ;
while (i <= endA && j <= endB) {
const x = a[i], y = b[j];
if (x < y) { indices[offset++] = x; i++; }
else if (x > y) { indices[offset++] = y; j++; }
else { indices[offset++] = x; i++; j++; }
}
// insert the "tail"
for (; i < lenA; i++) indices[offset++] = a[i];
for (; j < lenB; j++) indices[offset++] = b[j];
return OrderedSet.ofSortedArray(indices);
}
const _iRA = IntPair.zero(), _iRB = IntPair.zero();
function intersectRR(a: number, b: number) {
if (!areRangesIntersecting(a, b)) return OrderedSet.Empty;
IntPair.unpack(a, _iRA);
IntPair.unpack(b, _iRB);
return OrderedSet.ofRange(Math.max(_iRA.fst, _iRB.fst), Math.min(_iRA.snd, _iRB.snd));
}
const _iAR = IntPair.zero();
function intersectAR(a: Nums, r: number) {
if (!S.size(r)) return OrderedSet.Empty;
IntPair.unpack(r, _iAR);
const { start, end } = getStartEnd(a, _iAR.fst, _iAR.snd);
const resultSize = end - start;
if (!resultSize) return OrderedSet.Empty;
const indices = new Int32Array(resultSize);
let offset = 0;
for (let i = start; i < end; i++) {
indices[offset++] = a[i];
}
return OrderedSet.ofSortedArray(indices);
}
function intersectAA(xs: Nums, ys: Nums) {
let { i: sI, j: sJ, endA, endB } = getMaxIntersectionRange(xs, ys);
let i = sI, j = sJ;
let resultSize = 0;
while (i <= endA && j <= endB) {
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 = sI;
j = sJ;
while (i <= endA && j <= endB) {
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);
}
const _sRA = IntPair.zero(), _sRB = IntPair.zero();
function substractRR(a: number, b: number) {
IntPair.unpack(a, _sRA);
IntPair.unpack(b, _sRB);
if (_sRA.snd < _sRA.fst || _sRB.snd < _sRB.fst) return a;
// is A subset of B? ==> Empty
if (isRangeSubset(b, a)) return OrderedSet.Empty;
if (isRangeSubset(a, b)) {
// this splits the interval into two, gotta represent it as a set.
const l = _sRB.fst - _sRA.fst, r = _sRA.snd - _sRB.snd;
const ret = new Int32Array(l + r);
let offset = 0;
for (let i = 0; i < l; i++) ret[offset++] = _sRA.fst + i;
for (let i = 1; i <= r; i++) ret[offset++] = _sRB.snd + i;
return OrderedSet.ofSortedArray(ret);
}
// non intersecting ranges are handled by top-level substract.
// at this point, b either contains rA.fst or rA.snd, but not both.
if (_sRA.fst < _sRB.fst) return OrderedSet.ofRange(_sRA.fst, _sRB.fst - 1);
return OrderedSet.ofRange(_sRB.snd + 1, _sRA.snd);
}
const _sAR = IntPair.zero();
function subtractAR(a: Nums, r: number) {
IntPair.unpack(r, _sAR);
if (_sAR.snd < _sAR.fst) return a;
const min = _sAR.fst, max = _sAR.snd;
const { start, end } = getStartEnd(a, min, max);
const size = a.length - (end - start);
if (size <= 0) return OrderedSet.Empty;
const ret = new Int32Array(size);
let offset = 0;
for (let i = 0; i < start; i++) ret[offset++] = a[i];
for (let i = end, _i = a.length; i < _i; i++) ret[offset++] = a[i];
return OrderedSet.ofSortedArray(ret);
}
const _sAR1 = IntPair.zero();
function subtractRA(r: number, b: Nums) {
IntPair.unpack(r, _sAR1);
if (_sAR1.snd < _sAR1.fst) return r;
const min = _sAR1.fst, max = _sAR1.snd;
const rSize = max - min + 1;
const { start, end } = getStartEnd(b, min, max);
const commonCount = end - start;
const resultSize = rSize - commonCount;
if (resultSize <= 0) return OrderedSet.Empty;
const ret = new Int32Array(resultSize);
const li = b.length - 1;
const fst = b[Math.min(start, li)], last = b[Math.min(end, li)];
let offset = 0;
for (let i = min; i < fst; i++) ret[offset++] = i;
for (let i = fst; i <= last; i++) {
if (binarySearch(b, i) < 0) ret[offset++] = i;
}
for (let i = last + 1; i <= max; i++) ret[offset++] = i;
return OrderedSet.ofSortedArray(ret);
}
function subtractAA(a: Nums, b: Nums) {
const lenA = a.length;
let { i: sI, j: sJ, endA, endB } = getMaxIntersectionRange(a, b);
let i = sI, j = sJ;
let commonCount = 0;
while (i <= endA && j <= endB) {
const x = a[i], y = b[j];
if (x < y) { i++; }
else if (x > y) { j++; }
else { i++; j++; commonCount++; }
}
if (!commonCount) return a;
if (commonCount >= lenA) return OrderedSet.Empty;
const indices = new Int32Array(lenA - commonCount);
let offset = 0;
// insert the "prefix"
for (let k = 0; k < sI; k++) indices[offset++] = a[k];
i = sI;
j = sJ;
while (i <= endA && j <= endB) {
const x = a[i], y = b[j];
if (x < y) { indices[offset++] = x; i++; }
else if (x > y) { j++; }
else { i++; j++; }
}
// insert the "tail"
for (; i < lenA; i++) indices[offset++] = a[i];
return OrderedSet.ofSortedArray(indices);
}
export default OrderedSet
\ No newline at end of file
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
* @author David Sehnal <david.sehnal@gmail.com> * @author David Sehnal <david.sehnal@gmail.com>
*/ */
import Iterator from './iterator'
import { hash3, hash4 } from './hash-functions' import { hash3, hash4 } from './hash-functions'
/** An immutable ordered set. */ /** An immutable ordered set. */
...@@ -12,8 +11,7 @@ interface OrderedSet { ...@@ -12,8 +11,7 @@ interface OrderedSet {
readonly size: number, readonly size: number,
has(x: number): boolean, has(x: number): boolean,
indexOf(x: number): number, indexOf(x: number): number,
elementAt(i: number): number, elementAt(i: number): number
elements(): Iterator<number>
} }
interface Impl extends OrderedSet { interface Impl extends OrderedSet {
...@@ -26,7 +24,6 @@ class RangeImpl implements Impl { ...@@ -26,7 +24,6 @@ class RangeImpl implements Impl {
has(x: number) { return x >= this.min && x <= this.max; } has(x: number) { return x >= this.min && x <= this.max; }
indexOf(x: number) { return x >= this.min && x <= this.max ? x - this.min : -1; } indexOf(x: number) { return x >= this.min && x <= this.max ? x - this.min : -1; }
elementAt(i: number) { return this.min + i; } elementAt(i: number) { return this.min + i; }
elements() { return Iterator.Range(this.min, this.max); }
constructor(public min: number, public max: number) { constructor(public min: number, public max: number) {
this.size = max - min + 1; this.size = max - min + 1;
...@@ -40,7 +37,6 @@ class ArrayImpl implements Impl { ...@@ -40,7 +37,6 @@ class ArrayImpl implements Impl {
has(x: number) { return x >= this.min && x <= this.max && binarySearch(this.values, x) >= 0; } 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; } indexOf(x: number) { return x >= this.min && x <= this.max ? binarySearch(this.values, x) : -1; }
elementAt(i: number) { return this.values[i]; } elementAt(i: number) { return this.values[i]; }
elements() { return Iterator.Array(this.values); }
constructor(public values: ArrayLike<number>) { constructor(public values: ArrayLike<number>) {
this.min = values[0]; this.min = values[0];
......
...@@ -8,6 +8,7 @@ import Iterator from '../collections/iterator' ...@@ -8,6 +8,7 @@ import Iterator from '../collections/iterator'
import IntPair from '../collections/int-pair' import IntPair from '../collections/int-pair'
import * as Sort from '../collections/sort' import * as Sort from '../collections/sort'
import OrderedSet from '../collections/ordered-set' import OrderedSet from '../collections/ordered-set'
import OrderedSet1 from '../collections/ordered-set.1'
import LinkedIndex from '../collections/linked-index' import LinkedIndex from '../collections/linked-index'
import MultiSet from '../collections/multi-set' import MultiSet from '../collections/multi-set'
...@@ -128,11 +129,17 @@ describe('qsort-dual array', () => { ...@@ -128,11 +129,17 @@ describe('qsort-dual array', () => {
test('shuffled', data, true); test('shuffled', data, true);
}) })
describe('range set', () => { function ordSetToArray(set: OrderedSet) {
const ret = [];
for (let i = 0; i < set.size; i++) ret.push(set.elementAt(i));
return ret;
}
describe('ordered set', () => {
function testEq(name: string, set: OrderedSet, expected: number[]) { function testEq(name: string, set: OrderedSet, expected: number[]) {
it(name, () => { it(name, () => {
// copy the arrays to ensure "compatibility" between typed and native arrays // copy the arrays to ensure "compatibility" between typed and native arrays
expect(Array.prototype.slice.call(iteratorToArray(set.elements()))).toEqual(Array.prototype.slice.call(expected)); expect(Array.prototype.slice.call(ordSetToArray(set))).toEqual(Array.prototype.slice.call(expected));
}); });
} }
...@@ -266,6 +273,151 @@ describe('range set', () => { ...@@ -266,6 +273,151 @@ describe('range set', () => {
testEq('subtract AA2', OrderedSet.subtract(arr136, OrderedSet.ofSortedArray([0, 1, 6])), [3]); testEq('subtract AA2', OrderedSet.subtract(arr136, OrderedSet.ofSortedArray([0, 1, 6])), [3]);
}); });
describe('ordered set 1', () => {
function ordSet1ToArray(set: OrderedSet1) {
const ret = [];
for (let i = 0, _i = OrderedSet1.size(set); i < _i; i++) ret.push(OrderedSet1.elementAt(set, i));
return ret;
}
function testEq(name: string, set: OrderedSet1, expected: number[]) {
it(name, () => {
// copy the arrays to ensure "compatibility" between typed and native arrays
expect(Array.prototype.slice.call(ordSet1ToArray(set))).toEqual(Array.prototype.slice.call(expected));
});
}
const empty = OrderedSet1.Empty;
const singleton10 = OrderedSet1.ofSingleton(10);
const range1_4 = OrderedSet1.ofRange(1, 4);
const arr136 = OrderedSet1.ofSortedArray([1, 3, 6]);
testEq('empty', empty, []);
testEq('singleton', singleton10, [10]);
testEq('range', range1_4, [1, 2, 3, 4]);
testEq('sorted array', arr136, [1, 3, 6]);
it('equality', () => {
expect(OrderedSet1.areEqual(empty, singleton10)).toBe(false);
expect(OrderedSet1.areEqual(singleton10, singleton10)).toBe(true);
expect(OrderedSet1.areEqual(range1_4, singleton10)).toBe(false);
expect(OrderedSet1.areEqual(arr136, OrderedSet1.ofSortedArray([1, 3, 6]))).toBe(true);
expect(OrderedSet1.areEqual(arr136, OrderedSet1.ofSortedArray([1, 4, 6]))).toBe(false);
});
it('areIntersecting', () => {
expect(OrderedSet1.areIntersecting(range1_4, arr136)).toBe(true);
expect(OrderedSet1.areIntersecting(empty, empty)).toBe(true);
expect(OrderedSet1.areIntersecting(empty, singleton10)).toBe(false);
expect(OrderedSet1.areIntersecting(empty, range1_4)).toBe(false);
expect(OrderedSet1.areIntersecting(empty, arr136)).toBe(false);
});
it('isSubset', () => {
expect(OrderedSet1.isSubset(singleton10, empty)).toBe(true);
expect(OrderedSet1.isSubset(range1_4, empty)).toBe(true);
expect(OrderedSet1.isSubset(arr136, empty)).toBe(true);
expect(OrderedSet1.isSubset(empty, empty)).toBe(true);
expect(OrderedSet1.isSubset(empty, singleton10)).toBe(false);
expect(OrderedSet1.isSubset(empty, range1_4)).toBe(false);
expect(OrderedSet1.isSubset(empty, arr136)).toBe(false);
expect(OrderedSet1.isSubset(singleton10, range1_4)).toBe(false);
expect(OrderedSet1.isSubset(range1_4, OrderedSet1.ofRange(2, 3))).toBe(true);
expect(OrderedSet1.isSubset(arr136, range1_4)).toBe(false);
expect(OrderedSet1.isSubset(arr136, arr136)).toBe(true);
expect(OrderedSet1.isSubset(arr136, OrderedSet1.ofSortedArray([1, 3]))).toBe(true);
expect(OrderedSet1.isSubset(arr136, OrderedSet1.ofSortedArray([1, 3, 7]))).toBe(false);
expect(OrderedSet1.isSubset(OrderedSet1.ofSortedArray([0, 1, 2, 3, 7, 10]), OrderedSet1.ofSortedArray([1, 3, 7]))).toBe(true);
expect(OrderedSet1.isSubset(arr136, OrderedSet1.ofSortedArray([1, 3, 10, 45]))).toBe(false);
});
it('access/membership', () => {
expect(OrderedSet1.has(empty, 10)).toBe(false);
expect(OrderedSet1.indexOf(empty, 10)).toBe(-1);
expect(OrderedSet1.has(singleton10, 10)).toBe(true);
expect(OrderedSet1.has(singleton10, 11)).toBe(false);
expect(OrderedSet1.indexOf(singleton10, 10)).toBe(0);
expect(OrderedSet1.indexOf(singleton10, 11)).toBe(-1);
expect(OrderedSet1.has(range1_4, 4)).toBe(true);
expect(OrderedSet1.has(range1_4, 5)).toBe(false);
expect(OrderedSet1.indexOf(range1_4, 4)).toBe(3);
expect(OrderedSet1.indexOf(range1_4, 11)).toBe(-1);
expect(OrderedSet1.has(arr136, 3)).toBe(true);
expect(OrderedSet1.has(arr136, 4)).toBe(false);
expect(OrderedSet1.indexOf(arr136, 3)).toBe(1);
expect(OrderedSet1.indexOf(arr136, 11)).toBe(-1);
});
it('interval range', () => {
expect(OrderedSet1.getIntervalRange(empty, 9, 11)).toEqual({ start: 0, end: 0 });
expect(OrderedSet1.getIntervalRange(empty, -9, -6)).toEqual({ start: 0, end: 0 });
expect(OrderedSet1.getIntervalRange(singleton10, 9, 11)).toEqual({ start: 0, end: 1 });
expect(OrderedSet1.getIntervalRange(range1_4, 2, 3)).toEqual({ start: 1, end: 3 });
expect(OrderedSet1.getIntervalRange(range1_4, -10, 2)).toEqual({ start: 0, end: 2 });
expect(OrderedSet1.getIntervalRange(range1_4, -10, 20)).toEqual({ start: 0, end: 4 });
expect(OrderedSet1.getIntervalRange(range1_4, 3, 20)).toEqual({ start: 2, end: 4 });
expect(OrderedSet1.getIntervalRange(arr136, 0, 1)).toEqual({ start: 0, end: 1 });
expect(OrderedSet1.getIntervalRange(arr136, 0, 3)).toEqual({ start: 0, end: 2 });
expect(OrderedSet1.getIntervalRange(arr136, 0, 4)).toEqual({ start: 0, end: 2 });
expect(OrderedSet1.getIntervalRange(arr136, 2, 4)).toEqual({ start: 1, end: 2 });
expect(OrderedSet1.getIntervalRange(arr136, 2, 7)).toEqual({ start: 1, end: 3 });
})
testEq('union ES', OrderedSet1.union(empty, singleton10), [10]);
testEq('union ER', OrderedSet1.union(empty, range1_4), [1, 2, 3, 4]);
testEq('union EA', OrderedSet1.union(empty, arr136), [1, 3, 6]);
testEq('union SS', OrderedSet1.union(singleton10, OrderedSet1.ofSingleton(16)), [10, 16]);
testEq('union SR', OrderedSet1.union(range1_4, singleton10), [1, 2, 3, 4, 10]);
testEq('union SA', OrderedSet1.union(arr136, singleton10), [1, 3, 6, 10]);
testEq('union SA1', OrderedSet1.union(arr136, OrderedSet1.ofSingleton(3)), [1, 3, 6]);
testEq('union RR', OrderedSet1.union(range1_4, range1_4), [1, 2, 3, 4]);
testEq('union RR1', OrderedSet1.union(range1_4, OrderedSet1.ofRange(6, 7)), [1, 2, 3, 4, 6, 7]);
testEq('union RR2', OrderedSet1.union(range1_4, OrderedSet1.ofRange(3, 5)), [1, 2, 3, 4, 5]);
testEq('union RA', OrderedSet1.union(range1_4, arr136), [1, 2, 3, 4, 6]);
testEq('union AA', OrderedSet1.union(arr136, OrderedSet1.ofSortedArray([2, 4, 6, 7])), [1, 2, 3, 4, 6, 7]);
testEq('union AA1', OrderedSet1.union(arr136, OrderedSet1.ofSortedArray([2, 3, 4, 6, 7])), [1, 2, 3, 4, 6, 7]);
testEq('union AA2', OrderedSet1.union(arr136, OrderedSet1.ofSortedArray([2, 4, 5, 6, 7])), [1, 2, 3, 4, 5, 6, 7]);
testEq('intersect ES', OrderedSet1.intersect(empty, singleton10), []);
testEq('intersect ER', OrderedSet1.intersect(empty, range1_4), []);
testEq('intersect EA', OrderedSet1.intersect(empty, arr136), []);
testEq('intersect SS', OrderedSet1.intersect(singleton10, OrderedSet1.ofSingleton(16)), []);
testEq('intersect SS1', OrderedSet1.intersect(singleton10, singleton10), [10]);
testEq('intersect SR', OrderedSet1.intersect(range1_4, singleton10), []);
testEq('intersect RR', OrderedSet1.intersect(range1_4, range1_4), [1, 2, 3, 4]);
testEq('intersect RR2', OrderedSet1.intersect(range1_4, OrderedSet1.ofRange(3, 5)), [3, 4]);
testEq('intersect RA', OrderedSet1.intersect(range1_4, arr136), [1, 3]);
testEq('intersect AA', OrderedSet1.intersect(arr136, OrderedSet1.ofSortedArray([2, 3, 4, 6, 7])), [3, 6]);
testEq('subtract ES', OrderedSet1.subtract(empty, singleton10), []);
testEq('subtract ER', OrderedSet1.subtract(empty, range1_4), []);
testEq('subtract EA', OrderedSet1.subtract(empty, arr136), []);
testEq('subtract SS', OrderedSet1.subtract(singleton10, OrderedSet1.ofSingleton(16)), [10]);
testEq('subtract SS1', OrderedSet1.subtract(singleton10, singleton10), []);
testEq('subtract SR', OrderedSet1.subtract(range1_4, singleton10), [1, 2, 3, 4]);
testEq('subtract SR1', OrderedSet1.subtract(range1_4, OrderedSet1.ofSingleton(4)), [1, 2, 3]);
testEq('subtract SR2', OrderedSet1.subtract(range1_4, OrderedSet1.ofSingleton(3)), [1, 2, 4]);
testEq('subtract RR', OrderedSet1.subtract(range1_4, range1_4), []);
testEq('subtract RR1', OrderedSet1.subtract(range1_4, OrderedSet1.ofRange(3, 5)), [1, 2]);
testEq('subtract RA', OrderedSet1.subtract(range1_4, arr136), [2, 4]);
testEq('subtract RA1', OrderedSet1.subtract(range1_4, OrderedSet1.ofSortedArray([0, 1, 2, 3, 4, 7])), []);
testEq('subtract RA2', OrderedSet1.subtract(range1_4, OrderedSet1.ofSortedArray([0, 2, 3])), [1, 4]);
testEq('subtract AR', OrderedSet1.subtract(arr136, range1_4), [6]);
testEq('subtract AR1', OrderedSet1.subtract(arr136, OrderedSet1.ofRange(0, 10)), []);
testEq('subtract AR1', OrderedSet1.subtract(arr136, OrderedSet1.ofRange(2, 10)), [1]);
testEq('subtract AA', OrderedSet1.subtract(arr136, arr136), []);
testEq('subtract AA1', OrderedSet1.subtract(arr136, OrderedSet1.ofSortedArray([2, 3, 4, 6, 7])), [1]);
testEq('subtract AA2', OrderedSet1.subtract(arr136, OrderedSet1.ofSortedArray([0, 1, 6])), [3]);
});
describe('linked-index', () => { describe('linked-index', () => {
it('initial state', () => { it('initial state', () => {
const index = LinkedIndex(2); const index = LinkedIndex(2);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment