mark structs as merged and filter out at the end of bulk operations
instead of splicing out of the array immediately
This commit is contained in:
parent
90f2a06b5e
commit
17cc6d0226
@ -112,6 +112,9 @@ export const addStruct = (store, struct) => {
|
|||||||
export const findIndexSS = (structs, clock) => {
|
export const findIndexSS = (structs, clock) => {
|
||||||
let left = 0
|
let left = 0
|
||||||
let right = structs.length - 1
|
let right = structs.length - 1
|
||||||
|
while (/** @type any */(structs[right])._wasMerged) {
|
||||||
|
right--
|
||||||
|
}
|
||||||
let mid = structs[right]
|
let mid = structs[right]
|
||||||
let midclock = mid.id.clock
|
let midclock = mid.id.clock
|
||||||
if (midclock === clock) {
|
if (midclock === clock) {
|
||||||
@ -126,6 +129,9 @@ export const findIndexSS = (structs, clock) => {
|
|||||||
midclock = mid.id.clock
|
midclock = mid.id.clock
|
||||||
if (midclock <= clock) {
|
if (midclock <= clock) {
|
||||||
if (clock < midclock + mid.length) {
|
if (clock < midclock + mid.length) {
|
||||||
|
while (/** @type any */(structs[midindex])._wasMerged) {
|
||||||
|
midindex--
|
||||||
|
}
|
||||||
return midindex
|
return midindex
|
||||||
}
|
}
|
||||||
left = midindex + 1
|
left = midindex + 1
|
||||||
|
@ -180,6 +180,50 @@ const tryToMergeWithLeft = (structs, pos) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Array<AbstractStruct>} structs
|
||||||
|
* @param {number} pos
|
||||||
|
*/
|
||||||
|
const tryToMergeWithLeftNoSplice = (structs, pos) => {
|
||||||
|
const right = structs[pos]
|
||||||
|
if (/** @type any */(right)._wasMerged) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
let offset = 1
|
||||||
|
let left
|
||||||
|
do {
|
||||||
|
left = structs[pos - offset++]
|
||||||
|
} while (/** @type any */(left)._wasMerged)
|
||||||
|
if (left.deleted === right.deleted && left.constructor === right.constructor) {
|
||||||
|
if (left.mergeWith(right)) {
|
||||||
|
/** @type any */(right)._wasMerged = true
|
||||||
|
if (right instanceof Item && right.parentSub !== null && /** @type {AbstractType<any>} */ (right.parent)._map.get(right.parentSub) === right) {
|
||||||
|
/** @type {AbstractType<any>} */ (right.parent)._map.set(right.parentSub, /** @type {Item} */ (left))
|
||||||
|
}
|
||||||
|
right.id = left.id
|
||||||
|
right.length = left.length
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Array<AbstractStruct>} structs
|
||||||
|
* @param {number} mergedCount
|
||||||
|
*/
|
||||||
|
const filterMergedStructs = (structs, mergedCount) => {
|
||||||
|
let from = 0
|
||||||
|
for (let to = 0; to < structs.length - mergedCount; to++) {
|
||||||
|
while (/** @type any */(structs[from])._wasMerged) {
|
||||||
|
from++
|
||||||
|
}
|
||||||
|
structs[to] = structs[from]
|
||||||
|
from++
|
||||||
|
}
|
||||||
|
structs.splice(-mergedCount, mergedCount)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {DeleteSet} ds
|
* @param {DeleteSet} ds
|
||||||
* @param {StructStore} store
|
* @param {StructStore} store
|
||||||
@ -217,6 +261,7 @@ const tryMergeDeleteSet = (ds, store) => {
|
|||||||
// merge from right to left for better efficiecy and so we don't miss any merge targets
|
// merge from right to left for better efficiecy and so we don't miss any merge targets
|
||||||
ds.clients.forEach((deleteItems, client) => {
|
ds.clients.forEach((deleteItems, client) => {
|
||||||
const structs = /** @type {Array<GC|Item>} */ (store.clients.get(client))
|
const structs = /** @type {Array<GC|Item>} */ (store.clients.get(client))
|
||||||
|
let mergedCount = 0
|
||||||
for (let di = deleteItems.length - 1; di >= 0; di--) {
|
for (let di = deleteItems.length - 1; di >= 0; di--) {
|
||||||
const deleteItem = deleteItems[di]
|
const deleteItem = deleteItems[di]
|
||||||
// start with merging the item next to the last deleted item
|
// start with merging the item next to the last deleted item
|
||||||
@ -226,9 +271,12 @@ const tryMergeDeleteSet = (ds, store) => {
|
|||||||
si > 0 && struct.id.clock >= deleteItem.clock;
|
si > 0 && struct.id.clock >= deleteItem.clock;
|
||||||
struct = structs[--si]
|
struct = structs[--si]
|
||||||
) {
|
) {
|
||||||
tryToMergeWithLeft(structs, si)
|
mergedCount += tryToMergeWithLeftNoSplice(structs, si)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (mergedCount > 0) {
|
||||||
|
filterMergedStructs(structs, mergedCount)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,8 +366,13 @@ const cleanupTransactions = (transactionCleanups, i) => {
|
|||||||
const structs = /** @type {Array<GC|Item>} */ (store.clients.get(client))
|
const structs = /** @type {Array<GC|Item>} */ (store.clients.get(client))
|
||||||
// we iterate from right to left so we can safely remove entries
|
// we iterate from right to left so we can safely remove entries
|
||||||
const firstChangePos = math.max(findIndexSS(structs, beforeClock), 1)
|
const firstChangePos = math.max(findIndexSS(structs, beforeClock), 1)
|
||||||
|
let mergedCount = 0
|
||||||
for (let i = structs.length - 1; i >= firstChangePos; i--) {
|
for (let i = structs.length - 1; i >= firstChangePos; i--) {
|
||||||
tryToMergeWithLeft(structs, i)
|
mergedCount += tryToMergeWithLeftNoSplice(structs, i)
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line
|
||||||
|
if (mergedCount > 0) {
|
||||||
|
filterMergedStructs(structs, mergedCount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user