|
@@ -4,22 +4,22 @@
|
|
|
* @author David Sehnal <david.sehnal@gmail.com>
|
|
|
*/
|
|
|
|
|
|
-import OrderedSet from '../../mol-base/collections/ordered-set'
|
|
|
+import OrderedSet from '../../mol-base/collections/integer/ordered-set'
|
|
|
import Iterator from '../../mol-base/collections/iterator'
|
|
|
-import IntTuple from '../../mol-base/collections/int-tuple'
|
|
|
-import Interval from '../../mol-base/collections/interval'
|
|
|
+import Tuple from '../../mol-base/collections/integer/tuple'
|
|
|
+import Interval from '../../mol-base/collections/integer/interval'
|
|
|
import { sortArray } from '../../mol-base/collections/sort'
|
|
|
import { hash1 } from '../../mol-base/collections/hash-functions'
|
|
|
|
|
|
/** Long and painful implementation starts here */
|
|
|
|
|
|
export interface AtomSetElements { [id: number]: OrderedSet, offsets: number[], hashCode: number, keys: OrderedSet }
|
|
|
-export type AtomSetImpl = IntTuple | AtomSetElements
|
|
|
+export type AtomSetImpl = Tuple | AtomSetElements
|
|
|
|
|
|
export const Empty: AtomSetImpl = { offsets: [0], hashCode: 0, keys: OrderedSet.Empty };
|
|
|
|
|
|
-export function create(data: IntTuple | ArrayLike<IntTuple> | { [id: number]: OrderedSet }): AtomSetImpl {
|
|
|
- if (typeof data === 'number' || IntTuple.is(data)) return data;
|
|
|
+export function create(data: Tuple | ArrayLike<Tuple> | { [id: number]: OrderedSet }): AtomSetImpl {
|
|
|
+ if (typeof data === 'number' || Tuple.is(data)) return data;
|
|
|
if (isArrayLike(data)) return ofTuples(data);
|
|
|
return ofObject(data as { [id: number]: OrderedSet });
|
|
|
}
|
|
@@ -39,42 +39,42 @@ export function keyCount(set: AtomSetImpl): number {
|
|
|
}
|
|
|
|
|
|
export function hasKey(set: AtomSetImpl, key: number): boolean {
|
|
|
- if (typeof set === 'number') return IntTuple.fst(set) === key;
|
|
|
+ if (typeof set === 'number') return Tuple.fst(set) === key;
|
|
|
return OrderedSet.has((set as AtomSetElements).keys, key);
|
|
|
}
|
|
|
|
|
|
export function getKey(set: AtomSetImpl, index: number): number {
|
|
|
- if (typeof set === 'number') return IntTuple.fst(set);
|
|
|
+ if (typeof set === 'number') return Tuple.fst(set);
|
|
|
return OrderedSet.getAt((set as AtomSetElements).keys, index);
|
|
|
}
|
|
|
|
|
|
-export function hasTuple(set: AtomSetImpl, t: IntTuple): boolean {
|
|
|
- if (typeof set === 'number') return IntTuple.areEqual(t, set);
|
|
|
- const unit = IntTuple.fst(t);
|
|
|
+export function hasTuple(set: AtomSetImpl, t: Tuple): boolean {
|
|
|
+ if (typeof set === 'number') return Tuple.areEqual(t, set);
|
|
|
+ const unit = Tuple.fst(t);
|
|
|
return OrderedSet.has((set as AtomSetElements).keys, unit)
|
|
|
- ? OrderedSet.has((set as AtomSetElements)[unit], IntTuple.snd(t)) : false;
|
|
|
+ ? OrderedSet.has((set as AtomSetElements)[unit], Tuple.snd(t)) : false;
|
|
|
}
|
|
|
|
|
|
export function getByKey(set: AtomSetImpl, key: number): OrderedSet {
|
|
|
if (typeof set === 'number') {
|
|
|
- return IntTuple.fst(set) === key ? OrderedSet.ofSingleton(IntTuple.snd(set)) : OrderedSet.Empty;
|
|
|
+ return Tuple.fst(set) === key ? OrderedSet.ofSingleton(Tuple.snd(set)) : OrderedSet.Empty;
|
|
|
}
|
|
|
return OrderedSet.has((set as AtomSetElements).keys, key) ? (set as AtomSetElements)[key] : OrderedSet.Empty;
|
|
|
}
|
|
|
|
|
|
export function getByIndex(set: AtomSetImpl, index: number): OrderedSet {
|
|
|
- if (typeof set === 'number') return index === 0 ? OrderedSet.ofSingleton(IntTuple.snd(set)) : OrderedSet.Empty;
|
|
|
+ if (typeof set === 'number') return index === 0 ? OrderedSet.ofSingleton(Tuple.snd(set)) : OrderedSet.Empty;
|
|
|
const key = OrderedSet.getAt((set as AtomSetElements).keys, index);
|
|
|
return (set as AtomSetElements)[key] || OrderedSet.Empty;
|
|
|
}
|
|
|
|
|
|
-export function getAt(set: AtomSetImpl, i: number): IntTuple {
|
|
|
+export function getAt(set: AtomSetImpl, i: number): Tuple {
|
|
|
if (typeof set === 'number') return set;
|
|
|
return getAtE(set as AtomSetElements, i);
|
|
|
}
|
|
|
|
|
|
-export function indexOf(set: AtomSetImpl, t: IntTuple) {
|
|
|
- if (typeof set === 'number') return IntTuple.areEqual(set, t) ? 0 : -1;
|
|
|
+export function indexOf(set: AtomSetImpl, t: Tuple) {
|
|
|
+ if (typeof set === 'number') return Tuple.areEqual(set, t) ? 0 : -1;
|
|
|
return indexOfE(set as AtomSetElements, t);
|
|
|
}
|
|
|
|
|
@@ -85,14 +85,14 @@ export function size(set: AtomSetImpl) {
|
|
|
}
|
|
|
|
|
|
export function hashCode(set: AtomSetImpl) {
|
|
|
- if (typeof set === 'number') return IntTuple.hashCode(set);
|
|
|
+ if (typeof set === 'number') return Tuple.hashCode(set);
|
|
|
if ((set as AtomSetElements).hashCode !== -1) return (set as AtomSetElements).hashCode;
|
|
|
return computeHash((set as AtomSetElements));
|
|
|
}
|
|
|
|
|
|
export function areEqual(a: AtomSetImpl, b: AtomSetImpl) {
|
|
|
if (typeof a === 'number') {
|
|
|
- if (typeof b === 'number') return IntTuple.areEqual(a, b);
|
|
|
+ if (typeof b === 'number') return Tuple.areEqual(a, b);
|
|
|
return false;
|
|
|
}
|
|
|
if (typeof b === 'number') return false;
|
|
@@ -101,7 +101,7 @@ export function areEqual(a: AtomSetImpl, b: AtomSetImpl) {
|
|
|
|
|
|
export function areIntersecting(a: AtomSetImpl, b: AtomSetImpl) {
|
|
|
if (typeof a === 'number') {
|
|
|
- if (typeof b === 'number') return IntTuple.areEqual(a, b);
|
|
|
+ if (typeof b === 'number') return Tuple.areEqual(a, b);
|
|
|
return areIntersectingNE(a, b as AtomSetElements);
|
|
|
}
|
|
|
if (typeof b === 'number') return areIntersectingNE(b, a as AtomSetElements);
|
|
@@ -110,7 +110,7 @@ export function areIntersecting(a: AtomSetImpl, b: AtomSetImpl) {
|
|
|
|
|
|
export function intersect(a: AtomSetImpl, b: AtomSetImpl) {
|
|
|
if (typeof a === 'number') {
|
|
|
- if (typeof b === 'number') return IntTuple.areEqual(a, b) ? a : Empty;
|
|
|
+ if (typeof b === 'number') return Tuple.areEqual(a, b) ? a : Empty;
|
|
|
return intersectNE(a, b as AtomSetElements);
|
|
|
}
|
|
|
if (typeof b === 'number') return intersectNE(b, a as AtomSetElements);
|
|
@@ -119,7 +119,7 @@ export function intersect(a: AtomSetImpl, b: AtomSetImpl) {
|
|
|
|
|
|
export function subtract(a: AtomSetImpl, b: AtomSetImpl) {
|
|
|
if (typeof a === 'number') {
|
|
|
- if (typeof b === 'number') return IntTuple.areEqual(a, b) ? Empty : a;
|
|
|
+ if (typeof b === 'number') return Tuple.areEqual(a, b) ? Empty : a;
|
|
|
return subtractNE(a, b as AtomSetElements);
|
|
|
}
|
|
|
if (typeof b === 'number') return subtractEN(a as AtomSetElements, b);
|
|
@@ -134,7 +134,7 @@ export function unionMany(sets: ArrayLike<AtomSetImpl>) {
|
|
|
return findUnion(sets);
|
|
|
}
|
|
|
|
|
|
-class ElementsIterator implements Iterator<IntTuple> {
|
|
|
+class ElementsIterator implements Iterator<Tuple> {
|
|
|
private unit: number = 0;
|
|
|
private keyCount: number;
|
|
|
private setIndex = -1;
|
|
@@ -147,13 +147,13 @@ class ElementsIterator implements Iterator<IntTuple> {
|
|
|
next() { const value = this.move(); return { value, done: this.done } }
|
|
|
|
|
|
move() {
|
|
|
- if (this.done) return IntTuple.Zero;
|
|
|
+ if (this.done) return Tuple.Zero;
|
|
|
|
|
|
if (this.currentIndex >= this.currentSize) {
|
|
|
- if (!this.advance()) return IntTuple.Zero;
|
|
|
+ if (!this.advance()) return Tuple.Zero;
|
|
|
}
|
|
|
|
|
|
- return IntTuple.create(this.unit, OrderedSet.getAt(this.currentSet, this.currentIndex++));
|
|
|
+ return Tuple.create(this.unit, OrderedSet.getAt(this.currentSet, this.currentIndex++));
|
|
|
}
|
|
|
|
|
|
private advance() {
|
|
@@ -175,12 +175,12 @@ class ElementsIterator implements Iterator<IntTuple> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-export function values(set: AtomSetImpl): Iterator<IntTuple> {
|
|
|
- if (typeof set === 'number') return Iterator.Value(set as IntTuple);
|
|
|
+export function values(set: AtomSetImpl): Iterator<Tuple> {
|
|
|
+ if (typeof set === 'number') return Iterator.Value(set as Tuple);
|
|
|
return new ElementsIterator(set as AtomSetElements);
|
|
|
}
|
|
|
|
|
|
-function isArrayLike(x: any): x is ArrayLike<IntTuple> {
|
|
|
+function isArrayLike(x: any): x is ArrayLike<Tuple> {
|
|
|
return x && (typeof x.length === 'number' && (x instanceof Array || !!x.buffer));
|
|
|
}
|
|
|
|
|
@@ -193,7 +193,7 @@ function ofObject(data: { [id: number]: OrderedSet }) {
|
|
|
if (!keys.length) return Empty;
|
|
|
if (keys.length === 1) {
|
|
|
const set = data[keys[0]];
|
|
|
- if (OrderedSet.size(set) === 1) return IntTuple.create(keys[0], OrderedSet.getAt(set, 0));
|
|
|
+ if (OrderedSet.size(set) === 1) return Tuple.create(keys[0], OrderedSet.getAt(set, 0));
|
|
|
}
|
|
|
return ofObject1(keys, data);
|
|
|
}
|
|
@@ -202,7 +202,7 @@ function ofObject1(keys: number[], data: { [id: number]: OrderedSet }) {
|
|
|
if (keys.length === 1) {
|
|
|
const k = keys[0];
|
|
|
const set = data[k];
|
|
|
- if (OrderedSet.size(set) === 1) return IntTuple.create(k, OrderedSet.getAt(set, 0));
|
|
|
+ if (OrderedSet.size(set) === 1) return Tuple.create(k, OrderedSet.getAt(set, 0));
|
|
|
}
|
|
|
sortArray(keys);
|
|
|
return _createObjectOrdered(OrderedSet.ofSortedArray(keys), data);
|
|
@@ -212,7 +212,7 @@ function ofObjectOrdered(keys: OrderedSet, data: { [id: number]: OrderedSet }) {
|
|
|
if (OrderedSet.size(keys) === 1) {
|
|
|
const k = OrderedSet.getAt(keys, 0);
|
|
|
const set = data[k];
|
|
|
- if (OrderedSet.size(set) === 1) return IntTuple.create(k, OrderedSet.getAt(set, 0));
|
|
|
+ if (OrderedSet.size(set) === 1) return Tuple.create(k, OrderedSet.getAt(set, 0));
|
|
|
}
|
|
|
return _createObjectOrdered(keys, data);
|
|
|
}
|
|
@@ -256,12 +256,12 @@ function normalizeArray(xs: number[]) {
|
|
|
return xs;
|
|
|
}
|
|
|
|
|
|
-function ofTuples(xs: ArrayLike<IntTuple>) {
|
|
|
+function ofTuples(xs: ArrayLike<Tuple>) {
|
|
|
if (xs.length === 0) return Empty;
|
|
|
const sets: { [key: number]: number[] } = Object.create(null);
|
|
|
for (let i = 0, _i = xs.length; i < _i; i++) {
|
|
|
const x = xs[i];
|
|
|
- const u = IntTuple.fst(x), v = IntTuple.snd(x);
|
|
|
+ const u = Tuple.fst(x), v = Tuple.snd(x);
|
|
|
const set = sets[u];
|
|
|
if (set) set[set.length] = v;
|
|
|
else sets[u] = [v];
|
|
@@ -291,21 +291,21 @@ function getOffsetIndex(xs: ArrayLike<number>, value: number) {
|
|
|
return value < xs[min] ? min - 1 : min;
|
|
|
}
|
|
|
|
|
|
-function getAtE(set: AtomSetElements, i: number): IntTuple {
|
|
|
+function getAtE(set: AtomSetElements, i: number): Tuple {
|
|
|
const { offsets, keys } = set;
|
|
|
const o = getOffsetIndex(offsets, i);
|
|
|
if (o >= offsets.length - 1) return 0 as any;
|
|
|
const k = OrderedSet.getAt(keys, o);
|
|
|
const e = OrderedSet.getAt(set[k], i - offsets[o]);
|
|
|
- return IntTuple.create(k, e);
|
|
|
+ return Tuple.create(k, e);
|
|
|
}
|
|
|
|
|
|
-function indexOfE(set: AtomSetElements, t: IntTuple) {
|
|
|
+function indexOfE(set: AtomSetElements, t: Tuple) {
|
|
|
const { keys } = set;
|
|
|
- const u = IntTuple.fst(t);
|
|
|
+ const u = Tuple.fst(t);
|
|
|
const setIdx = OrderedSet.indexOf(keys, u);
|
|
|
if (setIdx < 0) return -1;
|
|
|
- const o = OrderedSet.indexOf(set[u], IntTuple.snd(t));
|
|
|
+ const o = OrderedSet.indexOf(set[u], Tuple.snd(t));
|
|
|
if (o < 0) return -1;
|
|
|
return set.offsets[setIdx] + o;
|
|
|
}
|
|
@@ -337,9 +337,9 @@ function areEqualEE(a: AtomSetElements, b: AtomSetElements) {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
-function areIntersectingNE(a: IntTuple, b: AtomSetElements) {
|
|
|
- const u = IntTuple.fst(a);
|
|
|
- return OrderedSet.has(b.keys, u) && OrderedSet.has(b[u], IntTuple.snd(a));
|
|
|
+function areIntersectingNE(a: Tuple, b: AtomSetElements) {
|
|
|
+ const u = Tuple.fst(a);
|
|
|
+ return OrderedSet.has(b.keys, u) && OrderedSet.has(b[u], Tuple.snd(a));
|
|
|
}
|
|
|
|
|
|
function areIntersectingEE(a: AtomSetElements, b: AtomSetElements) {
|
|
@@ -355,9 +355,9 @@ function areIntersectingEE(a: AtomSetElements, b: AtomSetElements) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
-function intersectNE(a: IntTuple, b: AtomSetElements) {
|
|
|
- const u = IntTuple.fst(a);
|
|
|
- return OrderedSet.has(b.keys, u) && OrderedSet.has(b[u], IntTuple.snd(a)) ? a : Empty;
|
|
|
+function intersectNE(a: Tuple, b: AtomSetElements) {
|
|
|
+ const u = Tuple.fst(a);
|
|
|
+ return OrderedSet.has(b.keys, u) && OrderedSet.has(b[u], Tuple.snd(a)) ? a : Empty;
|
|
|
}
|
|
|
|
|
|
function intersectEE(a: AtomSetElements, b: AtomSetElements) {
|
|
@@ -382,14 +382,14 @@ function intersectEE(a: AtomSetElements, b: AtomSetElements) {
|
|
|
return ofObjectOrdered(OrderedSet.ofSortedArray(keys), ret);
|
|
|
}
|
|
|
|
|
|
-function subtractNE(a: IntTuple, b: AtomSetElements) {
|
|
|
- const u = IntTuple.fst(a);
|
|
|
- return OrderedSet.has(b.keys, u) && OrderedSet.has(b[u], IntTuple.snd(a)) ? Empty : a;
|
|
|
+function subtractNE(a: Tuple, b: AtomSetElements) {
|
|
|
+ const u = Tuple.fst(a);
|
|
|
+ return OrderedSet.has(b.keys, u) && OrderedSet.has(b[u], Tuple.snd(a)) ? Empty : a;
|
|
|
}
|
|
|
|
|
|
-function subtractEN(a: AtomSetElements, b: IntTuple): AtomSetImpl {
|
|
|
+function subtractEN(a: AtomSetElements, b: Tuple): AtomSetImpl {
|
|
|
const aKeys = a.keys;
|
|
|
- const u = IntTuple.fst(b), v = IntTuple.snd(b);
|
|
|
+ const u = Tuple.fst(b), v = Tuple.snd(b);
|
|
|
if (!OrderedSet.has(aKeys, u) || !OrderedSet.has(a[u], v)) return a;
|
|
|
const set = a[u];
|
|
|
if (OrderedSet.size(set) === 1) {
|
|
@@ -470,7 +470,7 @@ function unionN(sets: ArrayLike<AtomSetImpl>, eCount: { count: number }) {
|
|
|
}
|
|
|
eCount.count = countE;
|
|
|
if (!countN) return Empty;
|
|
|
- if (countN === sets.length) return ofTuples(sets as ArrayLike<IntTuple>);
|
|
|
+ if (countN === sets.length) return ofTuples(sets as ArrayLike<Tuple>);
|
|
|
const packed = new Float64Array(countN);
|
|
|
let offset = 0;
|
|
|
for (let i = 0, _i = sets.length; i < _i; i++) {
|
|
@@ -490,12 +490,12 @@ function unionInto(data: { [key: number]: OrderedSet }, a: AtomSetElements) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-function unionIntoN(data: { [key: number]: OrderedSet }, a: IntTuple) {
|
|
|
- const u = IntTuple.fst(a);
|
|
|
+function unionIntoN(data: { [key: number]: OrderedSet }, a: Tuple) {
|
|
|
+ const u = Tuple.fst(a);
|
|
|
const set = data[u];
|
|
|
if (set) {
|
|
|
- data[u] = OrderedSet.union(set, OrderedSet.ofSingleton(IntTuple.snd(a)));
|
|
|
+ data[u] = OrderedSet.union(set, OrderedSet.ofSingleton(Tuple.snd(a)));
|
|
|
} else {
|
|
|
- data[u] = OrderedSet.ofSingleton(IntTuple.snd(a));
|
|
|
+ data[u] = OrderedSet.ofSingleton(Tuple.snd(a));
|
|
|
}
|
|
|
}
|