94 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			94 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/**
 | 
						|
 * @module utils
 | 
						|
 */
 | 
						|
 | 
						|
import { Tree } from '../lib/Tree.mjs'
 | 
						|
import * as ID from './ID.mjs'
 | 
						|
 | 
						|
class DSNode {
 | 
						|
  constructor (id, len, gc) {
 | 
						|
    this._id = id
 | 
						|
    this.len = len
 | 
						|
    this.gc = gc
 | 
						|
  }
 | 
						|
  clone () {
 | 
						|
    return new DSNode(this._id, this.len, this.gc)
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
export class DeleteStore extends Tree {
 | 
						|
  logTable () {
 | 
						|
    const deletes = []
 | 
						|
    this.iterate(null, null, n => {
 | 
						|
      deletes.push({
 | 
						|
        user: n._id.user,
 | 
						|
        clock: n._id.clock,
 | 
						|
        len: n.len,
 | 
						|
        gc: n.gc
 | 
						|
      })
 | 
						|
    })
 | 
						|
    console.table(deletes)
 | 
						|
  }
 | 
						|
  isDeleted (id) {
 | 
						|
    var n = this.findWithUpperBound(id)
 | 
						|
    return n !== null && n._id.user === id.user && id.clock < n._id.clock + n.len
 | 
						|
  }
 | 
						|
  mark (id, length, gc) {
 | 
						|
    if (length === 0) return
 | 
						|
    // Step 1. Unmark range
 | 
						|
    const leftD = this.findWithUpperBound(ID.createID(id.user, id.clock - 1))
 | 
						|
    // Resize left DSNode if necessary
 | 
						|
    if (leftD !== null && leftD._id.user === id.user) {
 | 
						|
      if (leftD._id.clock < id.clock && id.clock < leftD._id.clock + leftD.len) {
 | 
						|
        // node is overlapping. need to resize
 | 
						|
        if (id.clock + length < leftD._id.clock + leftD.len) {
 | 
						|
          // overlaps new mark range and some more
 | 
						|
          // create another DSNode to the right of new mark
 | 
						|
          this.put(new DSNode(ID.createID(id.user, id.clock + length), leftD._id.clock + leftD.len - id.clock - length, leftD.gc))
 | 
						|
        }
 | 
						|
        // resize left DSNode
 | 
						|
        leftD.len = id.clock - leftD._id.clock
 | 
						|
      } // Otherwise there is no overlapping
 | 
						|
    }
 | 
						|
    // Resize right DSNode if necessary
 | 
						|
    const upper = ID.createID(id.user, id.clock + length - 1)
 | 
						|
    const rightD = this.findWithUpperBound(upper)
 | 
						|
    if (rightD !== null && rightD._id.user === id.user) {
 | 
						|
      if (rightD._id.clock < id.clock + length && id.clock <= rightD._id.clock && id.clock + length < rightD._id.clock + rightD.len) { // we only consider the case where we resize the node
 | 
						|
        const d = id.clock + length - rightD._id.clock
 | 
						|
        rightD._id = ID.createID(rightD._id.user, rightD._id.clock + d)
 | 
						|
        rightD.len -= d
 | 
						|
      }
 | 
						|
    }
 | 
						|
    // Now we only have to delete all inner marks
 | 
						|
    const deleteNodeIds = []
 | 
						|
    this.iterate(id, upper, m => {
 | 
						|
      deleteNodeIds.push(m._id)
 | 
						|
    })
 | 
						|
    for (let i = deleteNodeIds.length - 1; i >= 0; i--) {
 | 
						|
      this.delete(deleteNodeIds[i])
 | 
						|
    }
 | 
						|
    let newMark = new DSNode(id, length, gc)
 | 
						|
    // Step 2. Check if we can extend left or right
 | 
						|
    if (leftD !== null && leftD._id.user === id.user && leftD._id.clock + leftD.len === id.clock && leftD.gc === gc) {
 | 
						|
      // We can extend left
 | 
						|
      leftD.len += length
 | 
						|
      newMark = leftD
 | 
						|
    }
 | 
						|
    const rightNext = this.find(ID.createID(id.user, id.clock + length))
 | 
						|
    if (rightNext !== null && rightNext._id.user === id.user && id.clock + length === rightNext._id.clock && gc === rightNext.gc) {
 | 
						|
      // We can merge newMark and rightNext
 | 
						|
      newMark.len += rightNext.len
 | 
						|
      this.delete(rightNext._id)
 | 
						|
    }
 | 
						|
    if (leftD !== newMark) {
 | 
						|
      // only put if we didn't extend left
 | 
						|
      this.put(newMark)
 | 
						|
    }
 | 
						|
  }
 | 
						|
  // TODO: exchange markDeleted for mark()
 | 
						|
  markDeleted (id, length) {
 | 
						|
    this.mark(id, length, false)
 | 
						|
  }
 | 
						|
}
 |