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

collections refactoring

parent 2f78edea
No related branches found
No related tags found
No related merge requests found
......@@ -11,46 +11,76 @@ import { sortArray } from './sort'
import { hash1 } from './hash-functions'
/** A map-like representation of integer set */
interface MultiSet { /*'@type': 'int-multi-set'*/ }
interface MultiSet { '@type': 'int-multi-set' }
namespace MultiSet {
export const Empty: MultiSet = { offsets: [0], hashCode: 0, keys: OrderedSet.Empty } as MultiSetElements as any;
export function create(data: IntTuple | ArrayLike<IntTuple> | IntTuple | { [id: number]: OrderedSet }): MultiSet {
if (typeof data === 'number') return data;
if (IntTuple.is(data)) return IntTuple.pack1(data) as number;
if (isArrayLike(data)) return ofTuples(data);
return ofObject(data as { [id: number]: OrderedSet });
if (IntTuple.is(data)) return IntTuple.pack1(data) as any;
if (isArrayLike(data)) return ofTuples(data) as any;
return ofObject(data as { [id: number]: OrderedSet }) as any;
}
export function keys(set: MultiSet): OrderedSet {
export const keys: (set: MultiSet) => OrderedSet = keysI as any;
export const keyCount: (set: MultiSet) => number = keyCountI as any;
export const hasKey: (set: MultiSet, key: number) => boolean = hasKeyI as any;
export const geyKey: (set: MultiSet, i: number) => number = getKeyI as any;
export const getByKey: (set: MultiSet, key: number) => OrderedSet = getByKeyI as any;
export const getByIndex: (set: MultiSet, i: number) => OrderedSet = getByIndexI as any;
export const has: (set: MultiSet, x: IntTuple) => boolean = hasI as any;
export const indexOf: (set: MultiSet, x: IntTuple) => number = indexOfI as any;
export const getAt: (set: MultiSet, i: number) => IntTuple = getAtI as any;
export const values: (set: MultiSet) => Iterator<IntTuple.Unpacked> = valuesI as any;
export const size: (set: MultiSet) => number = sizeI as any;
export const hashCode: (set: MultiSet) => number = hashCodeI as any;
export const areEqual: (a: MultiSet, b: MultiSet) => boolean = areEqualI as any;
export const areIntersecting: (a: MultiSet, b: MultiSet) => boolean = areIntersectingI as any;
export const union: (a: MultiSet, b: MultiSet) => MultiSet = unionI as any;
export const unionMany: (sets: MultiSet[]) => MultiSet = unionManyI as any;
export const intersect: (a: MultiSet, b: MultiSet) => MultiSet = intersectI as any;
export const subtract: (a: MultiSet, b: MultiSet) => MultiSet = subtractI as any;
}
export default MultiSet
/** Long and painful implementation starts here */
interface MultiSetElements { [id: number]: OrderedSet, offsets: number[], hashCode: number, keys: OrderedSet }
type MultiSetImpl = IntTuple | MultiSetElements
function keysI(set: MultiSetImpl): OrderedSet {
if (typeof set === 'number') return OrderedSet.ofSingleton(set);
return (set as MultiSetElements).keys;
}
export function keyCount(set: MultiSet): number {
function keyCountI(set: MultiSetImpl): number {
if (typeof set === 'number') return 1;
return OrderedSet.size((set as MultiSetElements).keys);
}
export function hasKey(set: MultiSet, key: number): boolean {
function hasKeyI(set: MultiSetImpl, key: number): boolean {
if (typeof set === 'number') return IntTuple.fst(set) === key;
return OrderedSet.has((set as MultiSetElements).keys, key);
}
export function getKey(set: MultiSet, index: number): number {
function getKeyI(set: MultiSetImpl, index: number): number {
if (typeof set === 'number') return IntTuple.fst(set);
return OrderedSet.getAt((set as MultiSetElements).keys, index);
}
export function has(set: MultiSet, t: IntTuple): boolean {
function hasI(set: MultiSetImpl, t: IntTuple): boolean {
if (typeof set === 'number') return IntTuple.areEqual(t, set);
IntTuple.unpack(t, _hasP);
return OrderedSet.has((set as MultiSetElements).keys, _hasP.fst) ? OrderedSet.has((set as MultiSetElements)[_hasP.fst], _hasP.snd) : false;
}
const _hasP = IntTuple.zero();
export function getByKey(set: MultiSet, key: number): OrderedSet {
function getByKeyI(set: MultiSetImpl, key: number): OrderedSet {
if (typeof set === 'number') {
IntTuple.unpack(set, _gS);
return _gS.fst === key ? OrderedSet.ofSingleton(_gS.snd) : OrderedSet.Empty;
......@@ -59,35 +89,35 @@ namespace MultiSet {
}
const _gS = IntTuple.zero();
export function getByIndex(set: MultiSet, index: number): OrderedSet {
function getByIndexI(set: MultiSetImpl, index: number): OrderedSet {
if (typeof set === 'number') return index === 0 ? OrderedSet.ofSingleton(IntTuple.snd(set)) : OrderedSet.Empty;
const key = OrderedSet.getAt((set as MultiSetElements).keys, index);
return (set as MultiSetElements)[key] || OrderedSet.Empty;
}
export function getAt(set: MultiSet, i: number): IntTuple {
function getAtI(set: MultiSetImpl, i: number): IntTuple {
if (typeof set === 'number') return set;
return getAtE(set as MultiSetElements, i);
}
export function indexOf(set: MultiSet, t: IntTuple) {
function indexOfI(set: MultiSetImpl, t: IntTuple) {
if (typeof set === 'number') return IntTuple.areEqual(set, t) ? 0 : -1;
return indexOfE(set as MultiSetElements, t);
}
/** Number elements in the "child" sets */
export function size(set: MultiSet) {
function sizeI(set: MultiSetImpl) {
if (typeof set === 'number') return 1;
return (set as MultiSetElements).offsets[(set as MultiSetElements).offsets.length - 1];
}
export function hashCode(set: MultiSet) {
function hashCodeI(set: MultiSetImpl) {
if (typeof set === 'number') return IntTuple.hashCode(set);
if ((set as MultiSetElements).hashCode !== -1) return (set as MultiSetElements).hashCode;
return computeHash((set as MultiSetElements));
}
export function areEqual(a: MultiSet, b: MultiSet): boolean {
function areEqualI(a: MultiSetImpl, b: MultiSetImpl) {
if (typeof a === 'number') {
if (typeof b === 'number') return IntTuple.areEqual(a, b);
return false;
......@@ -96,7 +126,7 @@ namespace MultiSet {
return areEqualEE(a as MultiSetElements, b as MultiSetElements);
}
export function areIntersecting(a: MultiSet, b: MultiSet): boolean {
function areIntersectingI(a: MultiSetImpl, b: MultiSetImpl) {
if (typeof a === 'number') {
if (typeof b === 'number') return IntTuple.areEqual(a, b);
return areIntersectingNE(a, b as MultiSetElements);
......@@ -105,29 +135,29 @@ namespace MultiSet {
return areIntersectingEE(a as MultiSetElements, b as MultiSetElements);
}
export function intersect(a: MultiSet, b: MultiSet): MultiSet {
function intersectI(a: MultiSetImpl, b: MultiSetImpl) {
if (typeof a === 'number') {
if (typeof b === 'number') return IntTuple.areEqual(a, b) ? a : Empty;
if (typeof b === 'number') return IntTuple.areEqual(a, b) ? a : MultiSet.Empty;
return intersectNE(a, b as MultiSetElements);
}
if (typeof b === 'number') return intersectNE(b, a as MultiSetElements);
return intersectEE(a as MultiSetElements, b as MultiSetElements);
}
export function subtract(a: MultiSet, b: MultiSet): MultiSet {
function subtractI(a: MultiSetImpl, b: MultiSetImpl) {
if (typeof a === 'number') {
if (typeof b === 'number') return IntTuple.areEqual(a, b) ? Empty : a;
if (typeof b === 'number') return IntTuple.areEqual(a, b) ? MultiSet.Empty : a;
return subtractNE(a, b as MultiSetElements);
}
if (typeof b === 'number') return subtractEN(a as MultiSetElements, b);
return subtractEE(a as MultiSetElements, b as MultiSetElements);
}
export function union(a: MultiSet, b: MultiSet): MultiSet {
function unionI(a: MultiSetImpl, b: MultiSetImpl) {
return findUnion([a, b]);
}
export function unionMany(sets: ArrayLike<MultiSet>): MultiSet {
function unionManyI(sets: ArrayLike<MultiSetImpl>) {
return findUnion(sets);
}
......@@ -175,13 +205,10 @@ namespace MultiSet {
}
}
export function values(set: MultiSet): Iterator<IntTuple.Unpacked> {
function valuesI(set: MultiSetImpl): Iterator<IntTuple.Unpacked> {
if (typeof set === 'number') return Iterator.Value(IntTuple.unpack1(set));
return new ElementsIterator(set as MultiSetElements);
}
}
interface MultiSetElements { [id: number]: OrderedSet, offsets: number[], hashCode: number, keys: OrderedSet }
function isArrayLike(x: any): x is ArrayLike<number> {
return x && (typeof x.length === 'number' && (x instanceof Array || !!x.buffer));
......@@ -259,7 +286,7 @@ function normalizeArray(xs: number[]) {
return xs;
}
function ofTuples(xs: ArrayLike<IntTuple>): MultiSet {
function ofTuples(xs: ArrayLike<IntTuple>) {
if (xs.length === 0) return MultiSet.Empty;
const sets: { [key: number]: number[] } = Object.create(null);
const p = IntTuple.zero();
......@@ -322,7 +349,7 @@ function computeHash(set: MultiSetElements) {
hash = (31 * hash + k) | 0;
hash = (31 * hash + OrderedSet.hashCode(set[k])) | 0;
}
hash = (31 * hash + MultiSet.size(set)) | 0;
hash = (31 * hash + sizeI(set)) | 0;
hash = hash1(hash);
set.hashCode = hash;
return hash;
......@@ -330,7 +357,7 @@ function computeHash(set: MultiSetElements) {
function areEqualEE(a: MultiSetElements, b: MultiSetElements) {
if (a === b) return true;
if (MultiSet.size(a) !== MultiSet.size(a)) return false;
if (sizeI(a) !== sizeI(a)) return false;
const keys = a.keys;
if (!OrderedSet.areEqual(keys, b.keys)) return false;
......@@ -393,7 +420,7 @@ function subtractNE(a: IntTuple, b: MultiSetElements) {
}
const _sEN = IntTuple.zero();
function subtractEN(a: MultiSetElements, b: IntTuple): MultiSet {
function subtractEN(a: MultiSetElements, b: IntTuple): MultiSetImpl {
const aKeys = a.keys;
IntTuple.unpack(b, _sEN);
if (!OrderedSet.has(aKeys, _sEN.fst) || !OrderedSet.has(a[_sEN.fst], _sEN.snd)) return a;
......@@ -439,10 +466,10 @@ function subtractEE(a: MultiSetElements, b: MultiSetElements) {
return ofObjectOrdered(OrderedSet.ofSortedArray(keys), ret);
}
function findUnion(sets: ArrayLike<MultiSet>) {
function findUnion(sets: ArrayLike<MultiSetImpl>) {
if (!sets.length) return MultiSet.Empty;
if (sets.length === 1) return sets[0];
if (sets.length === 2 && MultiSet.areEqual(sets[0], sets[1])) return sets[0];
if (sets.length === 2 && areEqualI(sets[0], sets[1])) return sets[0];
const eCount = { count: 0 };
const ns = unionN(sets, eCount);
......@@ -452,14 +479,14 @@ function findUnion(sets: ArrayLike<MultiSet>) {
const s = sets[i];
if (typeof s !== 'number') unionInto(ret, s as MultiSetElements);
}
if (MultiSet.size(ns) > 0) {
if (sizeI(ns as MultiSetImpl) > 0) {
if (typeof ns === 'number') unionIntoN(ret, ns);
else unionInto(ret, ns as MultiSetElements);
}
return ofObject(ret);
}
function unionN(sets: ArrayLike<MultiSet>, eCount: { count: number }) {
function unionN(sets: ArrayLike<MultiSetImpl>, eCount: { count: number }) {
let countN = 0, countE = 0;
for (let i = 0, _i = sets.length; i < _i; i++) {
if (typeof sets[i] === 'number') countN++;
......@@ -497,5 +524,3 @@ function unionIntoN(data: { [key: number]: OrderedSet }, a: IntTuple) {
data[_uIN.fst] = OrderedSet.ofSingleton(_uIN.snd);
}
}
\ No newline at end of file
export default MultiSet
\ No newline at end of file
......@@ -22,21 +22,22 @@ namespace OrderedSet {
return xs as any;
}
export const size: (set: OrderedSet) => number = sizeI as any;
export const has: (set: OrderedSet, x: number) => boolean = hasI as any;
export const indexOf: (set: OrderedSet, x: number) => number = indexOfI as any;
export const getAt: (set: OrderedSet, i: number) => number = getAtI as any;
export const min: (set: OrderedSet) => number = minI as any;
export const max: (set: OrderedSet) => number = maxI as any;
export const size: (set: OrderedSet) => number = sizeI as any;
export const hashCode: (set: OrderedSet) => number = hashCodeI as any;
export const areEqual: BinaryTest = areEqualI as any;
export const areIntersecting: BinaryTest = areIntersectingI as any;
export const isSubset: BinaryTest = isSubsetI as any;
export const areEqual: (a: OrderedSet, b: OrderedSet) => boolean = areEqualI as any;
export const areIntersecting: (a: OrderedSet, b: OrderedSet) => boolean = areIntersectingI as any;
export const isSubset: (a: OrderedSet, b: OrderedSet) => boolean = isSubsetI as any;
export const union: BinaryOp = unionI as any;
export const intersect: BinaryOp = intersectI as any;
export const subtract: BinaryOp = subtractI as any;
export const union: (a: OrderedSet, b: OrderedSet) => OrderedSet = unionI as any;
export const intersect: (a: OrderedSet, b: OrderedSet) => OrderedSet = intersectI as any;
export const subtract: (a: OrderedSet, b: OrderedSet) => OrderedSet = subtractI as any;
export const getInsertionIndex: (set: OrderedSet, x: number) => number = getInsertionIndexI as any;
export const getIntervalRange: (set: OrderedSet, min: number, max: number) => { start: number, end: number } = getIntervalRangeI as any;
......@@ -46,9 +47,6 @@ export default OrderedSet
/** Long and painful implementation starts here */
type BinaryTest = (a: OrderedSet, b: OrderedSet) => boolean
type BinaryOp = (a: OrderedSet, b: OrderedSet) => OrderedSet
type Range = IntTuple
type SortedArray = ArrayLike<number>
type OrderedSetImpl = Range | SortedArray
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment