fixed YMap
This commit is contained in:
parent
ff981a8697
commit
c188f813a4
@ -2,7 +2,6 @@
|
||||
export { Y } from './utils/Y.js'
|
||||
export { UndoManager } from './utils/UndoManager.js'
|
||||
export { Transaction } from './utils/Transaction.js'
|
||||
export { Delete } from './Delete.js'
|
||||
export { ItemJSON } from './structs/ItemJSON.js'
|
||||
export { ItemString } from './structs/ItemString.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 { 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 { isParentOf } from './utils/isParentOf.js'
|
||||
|
@ -51,7 +51,7 @@ export const splitItem = (transaction, leftItem, diff) => {
|
||||
foundOrigins.add(o)
|
||||
o = o.right
|
||||
}
|
||||
const right = leftItem.splitAt(diff)
|
||||
const right = leftItem.splitAt(transaction, diff)
|
||||
if (transaction.added.has(leftItem)) {
|
||||
transaction.added.add(right)
|
||||
} else if (transaction.deleted.has(leftItem)) {
|
||||
|
@ -2,11 +2,10 @@
|
||||
* @module types
|
||||
*/
|
||||
|
||||
import { AbstractType, typeMapDelete } from './AbstractType.js'
|
||||
import { ItemJSON } from '../structs/ItemJSON.js'
|
||||
import { AbstractType, typeMapDelete, typeMapSet, typeMapGet, typeMapHas } from './AbstractType.js'
|
||||
import { ItemType } from '../structs/ItemType.js' // eslint-disable-line
|
||||
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
|
||||
|
||||
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
|
||||
*/
|
||||
set (key, value) {
|
||||
this._transact(y => {
|
||||
const old = this._map.get(key) || null
|
||||
if (old !== null) {
|
||||
if (
|
||||
old.constructor === ItemJSON &&
|
||||
!old._deleted && old._content[0] === 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)
|
||||
}
|
||||
})
|
||||
if (this._y !== null) {
|
||||
this._y.transact(transaction => {
|
||||
typeMapSet(transaction, this, key, value)
|
||||
})
|
||||
} else {
|
||||
// @ts-ignore
|
||||
this._prelimContent.set(key, value)
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a specified element from this YMap.
|
||||
*
|
||||
* @param {string} key The key of the element to return.
|
||||
* @param {HistorySnapshot} [snapshot]
|
||||
* @param {string} key
|
||||
* @return {Object<string,any>|number|Array<any>|string|ArrayBuffer|AbstractType|undefined}
|
||||
*/
|
||||
get (key, snapshot) {
|
||||
let v = this._map.get(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]
|
||||
}
|
||||
}
|
||||
get (key) {
|
||||
return typeMapGet(this, key)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a boolean indicating whether the specified key exists or not.
|
||||
*
|
||||
* @param {string} key The key to test.
|
||||
* @param {HistorySnapshot} [snapshot]
|
||||
* @return {boolean}
|
||||
*/
|
||||
has (key, snapshot) {
|
||||
let v = this._map.get(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)
|
||||
has (key) {
|
||||
return typeMapHas(this, key)
|
||||
}
|
||||
}
|
||||
|
||||
export const readYMap = decoder => new YMap()
|
||||
/**
|
||||
* @param {decoding.Decoder} decoder
|
||||
*/
|
||||
export const readYMap = decoder => new YMap()
|
||||
|
@ -2,7 +2,6 @@
|
||||
* @module types
|
||||
*/
|
||||
|
||||
import { logItemHelper } from '../structs/AbstractItem.js/index.js'
|
||||
import { ItemEmbed } from '../structs/ItemEmbed.js'
|
||||
import { ItemString } from '../structs/ItemString.js'
|
||||
import { ItemFormat } from '../structs/ItemFormat.js'
|
||||
|
@ -3,7 +3,6 @@
|
||||
*/
|
||||
|
||||
import { Transaction } from '../utils/Transaction.js' // eslint-disable-line
|
||||
import { logItemHelper } from '../structs/AbstractItem.js'
|
||||
import { YMap } from './YMap.js'
|
||||
import * as encoding from 'lib0/encoding.js'
|
||||
import * as decoding from 'lib0/decoding.js'
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
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
|
||||
|
||||
/**
|
||||
|
@ -3,8 +3,7 @@ import * as encoding from 'lib0/encoding.js'
|
||||
import * as decoding from 'lib0/decoding.js'
|
||||
import { StructStore, getItemRange } from './StructStore.js' // eslint-disable-line
|
||||
import { Transaction } from './Transaction.js' // eslint-disable-line
|
||||
import * as error from 'lib0/error.js'
|
||||
import { ID } from './ID.js'
|
||||
import { ID } from './ID.js' // eslint-disable-line
|
||||
|
||||
class DeleteItem {
|
||||
/**
|
||||
|
@ -2,11 +2,9 @@
|
||||
* @module utils
|
||||
*/
|
||||
|
||||
import { getStruct } from '../utils/structReferences.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 { Item } from '../structs/AbstractItem.js/index.js' // eslint-disable-line
|
||||
|
||||
class MissingEntry {
|
||||
constructor (decoder, missing, struct) {
|
||||
|
@ -3,24 +3,23 @@
|
||||
*/
|
||||
|
||||
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`.
|
||||
*
|
||||
* @param {Type | Y} parent
|
||||
* @param {Type | Y} child
|
||||
* @param {AbstractType} parent
|
||||
* @param {AbstractType} child
|
||||
* @return {Boolean} Whether `parent` is a parent of `child`.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const isParentOf = (parent, child) => {
|
||||
child = child._parent
|
||||
while (child !== null) {
|
||||
while (child._item !== null) {
|
||||
if (child === parent) {
|
||||
return true
|
||||
}
|
||||
child = child._parent
|
||||
child = child._item.parent
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
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
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
import * as encoding from 'lib0/encoding.js'
|
||||
import * as decoding from 'lib0/decoding.js'
|
||||
import { AbstractStruct, AbstractRef } from '../structs/AbstractStruct.js'
|
||||
import { ID, createID, writeID, writeNullID } from './ID.js'
|
||||
import * as binary from 'lib0/binary.js'
|
||||
import { Transaction } from './Transaction.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"],
|
||||
// "types": ["./src/utils/typedefs.js"]
|
||||
},
|
||||
"files": ["./src/index.js"]
|
||||
"exclude": ["./dist/**"]
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user