fixes and tests for add, remove, move and update

This commit is contained in:
Bruno Windels 2019-02-26 22:03:16 +01:00
parent 290886a5eb
commit 2e362d1bbd

View file

@ -62,19 +62,21 @@ export default class SortedMapList extends BaseObservableList {
constructor(sourceMap, comparator) { constructor(sourceMap, comparator) {
super(); super();
this._sourceMap = sourceMap; this._sourceMap = sourceMap;
this._comparator = comparator; this._comparator = (a, b) => comparator(a.value, b.value);
this._sortedPairs = null; this._sortedPairs = null;
this._mapSubscription = null; this._mapSubscription = null;
} }
onAdd(key, value) { onAdd(key, value) {
const idx = sortedIndex(this._sortedPairs, value, this._comparator); const pair = {key, value};
this._sortedPairs.splice(idx, 0, {key, value}); const idx = sortedIndex(this._sortedPairs, pair, this._comparator);
this._sortedPairs.splice(idx, 0, pair);
this.emitAdd(idx, value); this.emitAdd(idx, value);
} }
onRemove(key, value) { onRemove(key, value) {
const idx = sortedIndex(this._sortedPairs, value, this._comparator); const pair = {key, value};
const idx = sortedIndex(this._sortedPairs, pair, this._comparator);
// assert key === this._sortedPairs[idx].key; // assert key === this._sortedPairs[idx].key;
this._sortedPairs.splice(idx, 1); this._sortedPairs.splice(idx, 1);
this.emitRemove(idx, value); this.emitRemove(idx, value);
@ -83,11 +85,12 @@ export default class SortedMapList extends BaseObservableList {
onUpdate(key, value, params) { onUpdate(key, value, params) {
// TODO: suboptimal for performance, see above for idea with BST to speed this up if we need to // TODO: suboptimal for performance, see above for idea with BST to speed this up if we need to
const oldIdx = this._sortedPairs.findIndex(p => p.key === key); const oldIdx = this._sortedPairs.findIndex(p => p.key === key);
// neccesary to remove item from array before // neccesary to remove pair from array before
// doing sortedIndex as it relies on being sorted // doing sortedIndex as it relies on being sorted
this._sortedPairs.splice(oldIdx, 1); this._sortedPairs.splice(oldIdx, 1);
const newIdx = sortedIndex(this._sortedPairs, value, this._comparator); const pair = {key, value};
this._sortedPairs.splice(newIdx, 0, {key, value}); const newIdx = sortedIndex(this._sortedPairs, pair, this._comparator);
this._sortedPairs.splice(newIdx, 0, pair);
if (oldIdx !== newIdx) { if (oldIdx !== newIdx) {
this.emitMove(oldIdx, newIdx, value); this.emitMove(oldIdx, newIdx, value);
} }
@ -103,8 +106,8 @@ export default class SortedMapList extends BaseObservableList {
this._mapSubscription = this._sourceMap.subscribe(this); this._mapSubscription = this._sourceMap.subscribe(this);
this._sortedPairs = new Array(this._sourceMap.size); this._sortedPairs = new Array(this._sourceMap.size);
let i = 0; let i = 0;
for (let [, value] of this._sourceMap) { for (let [key, value] of this._sourceMap) {
this._sortedPairs[i] = value; this._sortedPairs[i] = {key, value};
++i; ++i;
} }
this._sortedPairs.sort(this._comparator); this._sortedPairs.sort(this._comparator);
@ -118,7 +121,7 @@ export default class SortedMapList extends BaseObservableList {
} }
get(index) { get(index) {
return this._sortedPairs[index]; return this._sortedPairs[index].value;
} }
get length() { get length() {
@ -126,7 +129,16 @@ export default class SortedMapList extends BaseObservableList {
} }
[Symbol.iterator]() { [Symbol.iterator]() {
return this._sortedPairs.values(); const it = this._sortedPairs.values();
return {
next() {
const v = it.next();
if (v.value) {
v.value = v.value.value;
}
return v;
}
}
} }
} }
@ -136,11 +148,15 @@ import ObservableMap from "../map/ObservableMap.js";
export function tests() { export function tests() {
return { return {
test_sortIndex(assert) { test_sortIndex(assert) {
let idx = sortedIndex([1, 5, 6, 8], 0, (a, b) => a - b); const a = [1, 5, 6, 8];
const cmp = (a, b) => a - b;
let idx = sortedIndex(a, 0, cmp);
assert.equal(idx, 0); assert.equal(idx, 0);
idx = sortedIndex([1, 5, 6, 8], 3, (a, b) => a - b); idx = sortedIndex(a, 3, cmp);
assert.equal(idx, 1); assert.equal(idx, 1);
idx = sortedIndex([1, 5, 6, 8], 8, (a, b) => a - b); idx = sortedIndex(a, 5, cmp);
assert.equal(idx, 1);
idx = sortedIndex(a, 8, cmp);
assert.equal(idx, 3); assert.equal(idx, 3);
}, },
@ -167,7 +183,100 @@ export function tests() {
const list = new SortedMapList(map, (a, b) => a - b); const list = new SortedMapList(map, (a, b) => a - b);
list.subscribe({}); //needed to populate iterator list.subscribe({}); //needed to populate iterator
assert.deepEqual(Array.from(list), [-5, 6, 50]); assert.deepEqual(Array.from(list), [-5, 6, 50]);
} assert.equal(list.length, 3);
},
test_add(assert) {
const map = new ObservableMap([["a", 50], ["b", 6], ["c", -5]]);
const list = new SortedMapList(map, (a, b) => a - b);
let fired = 0;
list.subscribe({
onAdd(idx, value) {
fired++;
assert.equal(idx, 2);
assert.equal(value, 20);
}
});
map.add("d", 20);
assert.equal(fired, 1);
assert.equal(list.length, 4);
},
test_remove(assert) {
const map = new ObservableMap([["a", 50], ["b", 6], ["c", -5]]);
const list = new SortedMapList(map, (a, b) => a - b);
let fired = 0;
list.subscribe({
onRemove(idx, value) {
fired++;
assert.equal(idx, 2);
assert.equal(value, 50);
}
});
map.remove("a");
assert.equal(fired, 1);
assert.equal(list.length, 2);
},
test_move_reference(assert) {
const a = {number: 3};
const map = new ObservableMap([
["a", a],
["b", {number: 11}],
["c", {number: 1}],
]);
const list = new SortedMapList(map, (a, b) => a.number - b.number);
let updateFired = 0, moveFired = 0;
list.subscribe({
onUpdate(idx, value, param) {
updateFired++;
assert.equal(idx, 2);
assert.equal(value, a);
assert.equal(param, "number");
},
onMove(oldIdx, newIdx, value) {
moveFired++;
assert.equal(oldIdx, 1);
assert.equal(newIdx, 2);
assert.equal(value, a);
}
});
a.number = 111;
map.update("a", "number");
assert.equal(moveFired, 1);
assert.equal(updateFired, 1);
},
test_update_without_move(assert) {
const a = {number: 3};
const map = new ObservableMap([
["a", a],
["b", {number: 11}],
["c", {number: 1}],
]);
const list = new SortedMapList(map, (a, b) => a.number - b.number);
let updateFired = 0, moveFired = 0;
list.subscribe({
onUpdate(idx, value, param) {
updateFired++;
assert.equal(idx, 1);
assert.equal(value, a);
assert.equal(param, "number");
},
onMove() {
moveFired++;
}
});
assert.deepEqual(Array.from(list).map(v => v.number), [1, 3, 11]);
// asume some part of a that doesn't affect
// sorting order has changed here
map.update("a", "number");
assert.equal(moveFired, 0);
assert.equal(updateFired, 1);
assert.deepEqual(Array.from(list).map(v => v.number), [1, 3, 11]);
},
} }
} }
//#endif //#endif