fixed YMap
This commit is contained in:
parent
ff981a8697
commit
c188f813a4
@ -2,7 +2,6 @@
|
|||||||
export { Y } from './utils/Y.js'
|
export { Y } from './utils/Y.js'
|
||||||
export { UndoManager } from './utils/UndoManager.js'
|
export { UndoManager } from './utils/UndoManager.js'
|
||||||
export { Transaction } from './utils/Transaction.js'
|
export { Transaction } from './utils/Transaction.js'
|
||||||
export { Delete } from './Delete.js'
|
|
||||||
export { ItemJSON } from './structs/ItemJSON.js'
|
export { ItemJSON } from './structs/ItemJSON.js'
|
||||||
export { ItemString } from './structs/ItemString.js'
|
export { ItemString } from './structs/ItemString.js'
|
||||||
export { ItemFormat } from './structs/ItemFormat.js'
|
export { ItemFormat } from './structs/ItemFormat.js'
|
||||||
@ -20,7 +19,5 @@ export { YXmlElement as XmlElement, YXmlFragment as XmlFragment } from './types/
|
|||||||
export { getRelativePosition, fromRelativePosition, equal as equalRelativePosition } from './utils/relativePosition.js'
|
export { getRelativePosition, fromRelativePosition, equal as equalRelativePosition } from './utils/relativePosition.js'
|
||||||
|
|
||||||
export { ID, createID } from './utils/ID.js'
|
export { ID, createID } from './utils/ID.js'
|
||||||
export { DeleteStore, DSNode } from './utils/DeleteSet.js/index.js'
|
|
||||||
export { deleteItemRange } from './utils/structManipulation.js'
|
|
||||||
export { integrateRemoteStructs } from './utils/integrateRemoteStructs.js'
|
export { integrateRemoteStructs } from './utils/integrateRemoteStructs.js'
|
||||||
export { isParentOf } from './utils/isParentOf.js'
|
export { isParentOf } from './utils/isParentOf.js'
|
||||||
|
@ -51,7 +51,7 @@ export const splitItem = (transaction, leftItem, diff) => {
|
|||||||
foundOrigins.add(o)
|
foundOrigins.add(o)
|
||||||
o = o.right
|
o = o.right
|
||||||
}
|
}
|
||||||
const right = leftItem.splitAt(diff)
|
const right = leftItem.splitAt(transaction, diff)
|
||||||
if (transaction.added.has(leftItem)) {
|
if (transaction.added.has(leftItem)) {
|
||||||
transaction.added.add(right)
|
transaction.added.add(right)
|
||||||
} else if (transaction.deleted.has(leftItem)) {
|
} else if (transaction.deleted.has(leftItem)) {
|
||||||
|
@ -2,11 +2,10 @@
|
|||||||
* @module types
|
* @module types
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { AbstractType, typeMapDelete } from './AbstractType.js'
|
import { AbstractType, typeMapDelete, typeMapSet, typeMapGet, typeMapHas } from './AbstractType.js'
|
||||||
import { ItemJSON } from '../structs/ItemJSON.js'
|
|
||||||
import { ItemType } from '../structs/ItemType.js' // eslint-disable-line
|
import { ItemType } from '../structs/ItemType.js' // eslint-disable-line
|
||||||
import { YEvent } from '../utils/YEvent.js'
|
import { YEvent } from '../utils/YEvent.js'
|
||||||
import { ItemBinary } from '../structs/ItemBinary.js'
|
import * as decoding from 'lib0/decoding.js' // eslint-disable-line
|
||||||
import { Transaction } from '../utils/Transaction.js' // eslint-disable-line
|
import { Transaction } from '../utils/Transaction.js' // eslint-disable-line
|
||||||
|
|
||||||
class YMapIterator {
|
class YMapIterator {
|
||||||
@ -159,94 +158,39 @@ export class YMap extends AbstractType {
|
|||||||
* @param {Object | string | number | AbstractType | ArrayBuffer } value The value of the element to add
|
* @param {Object | string | number | AbstractType | ArrayBuffer } value The value of the element to add
|
||||||
*/
|
*/
|
||||||
set (key, value) {
|
set (key, value) {
|
||||||
this._transact(y => {
|
if (this._y !== null) {
|
||||||
const old = this._map.get(key) || null
|
this._y.transact(transaction => {
|
||||||
if (old !== null) {
|
typeMapSet(transaction, this, key, value)
|
||||||
if (
|
})
|
||||||
old.constructor === ItemJSON &&
|
} else {
|
||||||
!old._deleted && old._content[0] === value
|
// @ts-ignore
|
||||||
) {
|
this._prelimContent.set(key, value)
|
||||||
// Trying to overwrite with same value
|
}
|
||||||
// break here
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
if (y !== null) {
|
|
||||||
old._delete(y)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let v
|
|
||||||
if (typeof value === 'function') {
|
|
||||||
v = new value() // eslint-disable-line new-cap
|
|
||||||
value = v
|
|
||||||
} else if (value instanceof Item) {
|
|
||||||
v = value
|
|
||||||
} else if (value != null && value.constructor === ArrayBuffer) {
|
|
||||||
v = new ItemBinary()
|
|
||||||
v._content = value
|
|
||||||
} else {
|
|
||||||
v = new ItemJSON()
|
|
||||||
v._content = [value]
|
|
||||||
}
|
|
||||||
v._right = old
|
|
||||||
v._right_origin = old
|
|
||||||
v._parent = this
|
|
||||||
v._parentSub = key
|
|
||||||
if (y !== null) {
|
|
||||||
v._integrate(y)
|
|
||||||
} else {
|
|
||||||
this._map.set(key, v)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a specified element from this YMap.
|
* Returns a specified element from this YMap.
|
||||||
*
|
*
|
||||||
* @param {string} key The key of the element to return.
|
* @param {string} key
|
||||||
* @param {HistorySnapshot} [snapshot]
|
* @return {Object<string,any>|number|Array<any>|string|ArrayBuffer|AbstractType|undefined}
|
||||||
*/
|
*/
|
||||||
get (key, snapshot) {
|
get (key) {
|
||||||
let v = this._map.get(key)
|
return typeMapGet(this, key)
|
||||||
if (v === undefined) {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
if (snapshot !== undefined) {
|
|
||||||
// iterate until found element that exists
|
|
||||||
while (!snapshot.sm.has(v._id.user) || v._id.clock >= snapshot.sm.get(v._id.user)) {
|
|
||||||
v = v._right
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isVisible(v, snapshot)) {
|
|
||||||
if (v instanceof Type) {
|
|
||||||
return v
|
|
||||||
} else if (v.constructor === ItemBinary) {
|
|
||||||
return v._content
|
|
||||||
} else {
|
|
||||||
return v._content[v._content.length - 1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a boolean indicating whether the specified key exists or not.
|
* Returns a boolean indicating whether the specified key exists or not.
|
||||||
*
|
*
|
||||||
* @param {string} key The key to test.
|
* @param {string} key The key to test.
|
||||||
* @param {HistorySnapshot} [snapshot]
|
* @return {boolean}
|
||||||
*/
|
*/
|
||||||
has (key, snapshot) {
|
has (key) {
|
||||||
let v = this._map.get(key)
|
return typeMapHas(this, key)
|
||||||
if (v === undefined) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if (snapshot !== undefined) {
|
|
||||||
// iterate until found element that exists
|
|
||||||
while (!snapshot.sm.has(v._id.user) || v._id.clock >= snapshot.sm.get(v._id.user)) {
|
|
||||||
v = v._right
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return isVisible(v, snapshot)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const readYMap = decoder => new YMap()
|
/**
|
||||||
|
* @param {decoding.Decoder} decoder
|
||||||
|
*/
|
||||||
|
export const readYMap = decoder => new YMap()
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
* @module types
|
* @module types
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { logItemHelper } from '../structs/AbstractItem.js/index.js'
|
|
||||||
import { ItemEmbed } from '../structs/ItemEmbed.js'
|
import { ItemEmbed } from '../structs/ItemEmbed.js'
|
||||||
import { ItemString } from '../structs/ItemString.js'
|
import { ItemString } from '../structs/ItemString.js'
|
||||||
import { ItemFormat } from '../structs/ItemFormat.js'
|
import { ItemFormat } from '../structs/ItemFormat.js'
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Transaction } from '../utils/Transaction.js' // eslint-disable-line
|
import { Transaction } from '../utils/Transaction.js' // eslint-disable-line
|
||||||
import { logItemHelper } from '../structs/AbstractItem.js'
|
|
||||||
import { YMap } from './YMap.js'
|
import { YMap } from './YMap.js'
|
||||||
import * as encoding from 'lib0/encoding.js'
|
import * as encoding from 'lib0/encoding.js'
|
||||||
import * as decoding from 'lib0/decoding.js'
|
import * as decoding from 'lib0/decoding.js'
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
import { YEvent } from '../utils/YEvent.js'
|
import { YEvent } from '../utils/YEvent.js'
|
||||||
|
|
||||||
import { Type } from './AbstractType.js/index.js.js.js.js' // eslint-disable-line
|
import { Type } from './AbstractType.js' // eslint-disable-line
|
||||||
import { Transaction } from '../utils/Transaction.js' // eslint-disable-line
|
import { Transaction } from '../utils/Transaction.js' // eslint-disable-line
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3,8 +3,7 @@ import * as encoding from 'lib0/encoding.js'
|
|||||||
import * as decoding from 'lib0/decoding.js'
|
import * as decoding from 'lib0/decoding.js'
|
||||||
import { StructStore, getItemRange } from './StructStore.js' // eslint-disable-line
|
import { StructStore, getItemRange } from './StructStore.js' // eslint-disable-line
|
||||||
import { Transaction } from './Transaction.js' // eslint-disable-line
|
import { Transaction } from './Transaction.js' // eslint-disable-line
|
||||||
import * as error from 'lib0/error.js'
|
import { ID } from './ID.js' // eslint-disable-line
|
||||||
import { ID } from './ID.js'
|
|
||||||
|
|
||||||
class DeleteItem {
|
class DeleteItem {
|
||||||
/**
|
/**
|
||||||
|
@ -2,11 +2,9 @@
|
|||||||
* @module utils
|
* @module utils
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { getStruct } from '../utils/structReferences.js'
|
|
||||||
import * as decoding from 'lib0/decoding.js'
|
import * as decoding from 'lib0/decoding.js'
|
||||||
import { GC } from '../structs/GC.js/index.js.js'
|
import { GC } from '../structs/GC.js'
|
||||||
import { Y } from '../utils/Y.js' // eslint-disable-line
|
import { Y } from '../utils/Y.js' // eslint-disable-line
|
||||||
import { Item } from '../structs/AbstractItem.js/index.js' // eslint-disable-line
|
|
||||||
|
|
||||||
class MissingEntry {
|
class MissingEntry {
|
||||||
constructor (decoder, missing, struct) {
|
constructor (decoder, missing, struct) {
|
||||||
|
@ -3,24 +3,23 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Y } from '../utils/Y.js' // eslint-disable-line
|
import { Y } from '../utils/Y.js' // eslint-disable-line
|
||||||
import { Type } from '../types/AbstractType.js/index.js.js.js.js' // eslint-disable-line
|
import { AbstractType } from '../types/AbstractType.js' // eslint-disable-line
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if `parent` is a parent of `child`.
|
* Check if `parent` is a parent of `child`.
|
||||||
*
|
*
|
||||||
* @param {Type | Y} parent
|
* @param {AbstractType} parent
|
||||||
* @param {Type | Y} child
|
* @param {AbstractType} child
|
||||||
* @return {Boolean} Whether `parent` is a parent of `child`.
|
* @return {Boolean} Whether `parent` is a parent of `child`.
|
||||||
*
|
*
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export const isParentOf = (parent, child) => {
|
export const isParentOf = (parent, child) => {
|
||||||
child = child._parent
|
while (child._item !== null) {
|
||||||
while (child !== null) {
|
|
||||||
if (child === parent) {
|
if (child === parent) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
child = child._parent
|
child = child._item.parent
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import * as ID from './ID.js'
|
import * as ID from './ID.js'
|
||||||
import { GC } from '../structs/GC.js/index.js.js'
|
import { GC } from '../structs/GC.js'
|
||||||
|
|
||||||
// TODO: Implement function to describe ranges
|
// TODO: Implement function to describe ranges
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import * as encoding from 'lib0/encoding.js'
|
import * as encoding from 'lib0/encoding.js'
|
||||||
import * as decoding from 'lib0/decoding.js'
|
import * as decoding from 'lib0/decoding.js'
|
||||||
import { AbstractStruct, AbstractRef } from '../structs/AbstractStruct.js'
|
import { AbstractStruct, AbstractRef } from '../structs/AbstractStruct.js'
|
||||||
import { ID, createID, writeID, writeNullID } from './ID.js'
|
|
||||||
import * as binary from 'lib0/binary.js'
|
import * as binary from 'lib0/binary.js'
|
||||||
import { Transaction } from './Transaction.js'
|
import { Transaction } from './Transaction.js'
|
||||||
import { findIndex } from './StructStore.js'
|
import { findIndex } from './StructStore.js'
|
||||||
|
@ -1,86 +0,0 @@
|
|||||||
import * as prng from 'lib0/prng.js'
|
|
||||||
import * as t from 'lib0/testing.js'
|
|
||||||
import { DeleteStore } from '../src/utils/DeleteStore.js'
|
|
||||||
import * as ID from '../src/utils/ID.js'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a DS to an array of length 10.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* const ds = new DeleteStore()
|
|
||||||
* ds.mark(ID.createID(0, 0), 1, false)
|
|
||||||
* ds.mark(ID.createID(0, 1), 1, true)
|
|
||||||
* ds.mark(ID.createID(0, 3), 1, false)
|
|
||||||
* dsToArray(ds) // => [0, 1, undefined, 0]
|
|
||||||
*
|
|
||||||
* @return {Array<(null|number)>} Array of numbers indicating if array[i] is deleted (0), garbage collected (1), or undeleted (undefined).
|
|
||||||
*/
|
|
||||||
const dsToArray = ds => {
|
|
||||||
const array = []
|
|
||||||
let i = 0
|
|
||||||
ds.iterate(null, null, n => {
|
|
||||||
// fill with null
|
|
||||||
while (i < n._id.clock) {
|
|
||||||
array[i++] = null
|
|
||||||
}
|
|
||||||
while (i < n._id.clock + n.len) {
|
|
||||||
array[i++] = n.gc ? 1 : 0
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return array
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {t.TestCase} tc
|
|
||||||
*/
|
|
||||||
export const testDeleteStore = tc => {
|
|
||||||
t.describe('Integrity tests')
|
|
||||||
const ds = new DeleteStore()
|
|
||||||
ds.mark(ID.createID(0, 1), 1, false)
|
|
||||||
ds.mark(ID.createID(0, 2), 1, false)
|
|
||||||
ds.mark(ID.createID(0, 3), 1, false)
|
|
||||||
t.compareArrays(dsToArray(ds), [null, 0, 0, 0])
|
|
||||||
ds.mark(ID.createID(0, 2), 1, true)
|
|
||||||
t.compareArrays(dsToArray(ds), [null, 0, 1, 0])
|
|
||||||
ds.mark(ID.createID(0, 1), 1, true)
|
|
||||||
t.compareArrays(dsToArray(ds), [null, 1, 1, 0])
|
|
||||||
ds.mark(ID.createID(0, 3), 1, true)
|
|
||||||
t.compareArrays(dsToArray(ds), [null, 1, 1, 1])
|
|
||||||
ds.mark(ID.createID(0, 5), 1, true)
|
|
||||||
ds.mark(ID.createID(0, 4), 1, true)
|
|
||||||
t.compareArrays(dsToArray(ds), [null, 1, 1, 1, 1, 1])
|
|
||||||
ds.mark(ID.createID(0, 0), 3, false)
|
|
||||||
t.compareArrays(dsToArray(ds), [0, 0, 0, 1, 1, 1])
|
|
||||||
}
|
|
||||||
|
|
||||||
export const testRepeatDeleteStoreTests = tc => {
|
|
||||||
const gen = tc.prng
|
|
||||||
const ds = new DeleteStore()
|
|
||||||
const dsArray = []
|
|
||||||
for (let i = 0; i < 200; i++) {
|
|
||||||
const pos = prng.int31(gen, 0, 10)
|
|
||||||
const len = prng.int31(gen, 0, 4)
|
|
||||||
const gc = prng.bool(gen)
|
|
||||||
ds.mark(ID.createID(0, pos), len, gc)
|
|
||||||
for (let j = 0; j < len; j++) {
|
|
||||||
dsArray[pos + j] = gc ? 1 : 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// fill empty fields
|
|
||||||
for (let i = 0; i < dsArray.length; i++) {
|
|
||||||
if (dsArray[i] !== 0 && dsArray[i] !== 1) {
|
|
||||||
dsArray[i] = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
t.compareArrays(dsToArray(ds), dsArray)
|
|
||||||
let size = 0
|
|
||||||
let lastEl = null
|
|
||||||
for (let i = 0; i < dsArray.length; i++) {
|
|
||||||
let el = dsArray[i]
|
|
||||||
if (lastEl !== el && el !== null) {
|
|
||||||
size++
|
|
||||||
}
|
|
||||||
lastEl = el
|
|
||||||
}
|
|
||||||
t.assert(size === ds.length)
|
|
||||||
}
|
|
@ -58,5 +58,5 @@
|
|||||||
"typeRoots": ["./src/utils/typedefs.js"],
|
"typeRoots": ["./src/utils/typedefs.js"],
|
||||||
// "types": ["./src/utils/typedefs.js"]
|
// "types": ["./src/utils/typedefs.js"]
|
||||||
},
|
},
|
||||||
"files": ["./src/index.js"]
|
"exclude": ["./dist/**"]
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user