mirror of
https://github.com/yjs/yjs.git
synced 2026-02-24 04:01:14 +01:00
rename AttributionManager=>IdMap
The "AttributionManager" will be an abstract class that maps data (probably using IdMap(s))
This commit is contained in:
@@ -102,8 +102,8 @@ export {
|
||||
IdSet,
|
||||
equalIdSets,
|
||||
createDeleteSetFromStructStore,
|
||||
AttributionManager,
|
||||
createAttributionManager
|
||||
IdMap,
|
||||
createIdMap
|
||||
} from './internals.js'
|
||||
|
||||
const glo = /** @type {any} */ (typeof globalThis !== 'undefined'
|
||||
|
||||
@@ -40,4 +40,4 @@ export * from './structs/ContentString.js'
|
||||
export * from './structs/ContentType.js'
|
||||
export * from './structs/Item.js'
|
||||
export * from './structs/Skip.js'
|
||||
export * from './utils/AttributionManager.js'
|
||||
export * from './utils/IdMap.js'
|
||||
|
||||
@@ -26,7 +26,7 @@ import {
|
||||
updateMarkerChanges,
|
||||
ContentType,
|
||||
warnPrematureAccess,
|
||||
ArraySearchMarker, UpdateDecoderV1, UpdateDecoderV2, UpdateEncoderV1, UpdateEncoderV2, ID, Doc, Item, Snapshot, Transaction, AttributionManager, // eslint-disable-line
|
||||
ArraySearchMarker, UpdateDecoderV1, UpdateDecoderV2, UpdateEncoderV1, UpdateEncoderV2, ID, Doc, Item, Snapshot, Transaction, IdMap, // eslint-disable-line
|
||||
snapshot
|
||||
} from '../internals.js'
|
||||
|
||||
@@ -999,13 +999,13 @@ export class YText extends AbstractType {
|
||||
* Note that deleted content that was not deleted in prevYdoc is rendered as an insertion with the
|
||||
* attribution `{ isDeleted: true, .. }`.
|
||||
*
|
||||
* @param {AttributionManager} [attributionManager]
|
||||
* @param {IdMap<any>} [idMap]
|
||||
* @param {Doc} [prevYdoc]
|
||||
* @return {import('../utils/Delta.js').Delta} The Delta representation of this type.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
getContent (attributionManager, prevYdoc) {
|
||||
getContent (idMap, prevYdoc) {
|
||||
this.doc ?? warnPrematureAccess()
|
||||
const prevSnapshot = prevYdoc ? snapshot(prevYdoc) : null
|
||||
const d = delta.create()
|
||||
|
||||
@@ -12,21 +12,21 @@ import * as array from 'lib0/array'
|
||||
* @param {T} attr
|
||||
*
|
||||
*/
|
||||
const amAttrsHas = (attrs, attr) => attrs.find(a => a === attr)
|
||||
const idmapAttrsHas = (attrs, attr) => attrs.find(a => a === attr)
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @param {Array<T>} a
|
||||
* @param {Array<T>} b
|
||||
*/
|
||||
export const amAttrsEqual = (a, b) => a.length === b.length && a.every(v => amAttrsHas(b, v))
|
||||
export const idmapAttrsEqual = (a, b) => a.length === b.length && a.every(v => idmapAttrsHas(b, v))
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @param {Array<T>} a
|
||||
* @param {Array<T>} b
|
||||
*/
|
||||
const amAttrRangeJoin = (a, b) => a.concat(b.filter(attr => !amAttrsHas(a, attr)))
|
||||
const idmapAttrRangeJoin = (a, b) => a.concat(b.filter(attr => !idmapAttrsHas(a, attr)))
|
||||
|
||||
/**
|
||||
* @template Attrs
|
||||
@@ -132,7 +132,7 @@ export class AttrRanges {
|
||||
// merge range with nextRange
|
||||
const largerRange = range.len > nextRange.len ? range : nextRange
|
||||
const smallerLen = range.len < nextRange.len ? range.len : nextRange.len
|
||||
ids[i] = new AttrRange(range.clock, smallerLen, amAttrRangeJoin(range.attrs, nextRange.attrs))
|
||||
ids[i] = new AttrRange(range.clock, smallerLen, idmapAttrRangeJoin(range.attrs, nextRange.attrs))
|
||||
if (range.len === nextRange.len) {
|
||||
ids.splice(i + 1, 1)
|
||||
} else {
|
||||
@@ -152,7 +152,7 @@ export class AttrRanges {
|
||||
for (i = 1, j = 1; i < ids.length; i++) {
|
||||
const left = ids[j - 1]
|
||||
const right = ids[i]
|
||||
if (left.clock + left.len === right.clock && amAttrsEqual(left.attrs, right.attrs)) {
|
||||
if (left.clock + left.len === right.clock && idmapAttrsEqual(left.attrs, right.attrs)) {
|
||||
ids[j - 1] = new AttrRange(left.clock, left.len + right.len, left.attrs)
|
||||
} else if (right.len !== 0) {
|
||||
if (j < i) {
|
||||
@@ -169,11 +169,11 @@ export class AttrRanges {
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @param {Array<AttributionManager<T>>} ams
|
||||
* @return {AttributionManager<T>} A fresh IdSet
|
||||
* @param {Array<IdMap<T>>} ams
|
||||
* @return {IdMap<T>} A fresh IdSet
|
||||
*/
|
||||
export const mergeAttributionManagers = ams => {
|
||||
const merged = createAttributionManager()
|
||||
export const mergeIdMaps = ams => {
|
||||
const merged = createIdMap()
|
||||
for (let amsI = 0; amsI < ams.length; amsI++) {
|
||||
ams[amsI].clients.forEach((rangesLeft, client) => {
|
||||
if (!merged.clients.has(client)) {
|
||||
@@ -196,7 +196,7 @@ export const mergeAttributionManagers = ams => {
|
||||
/**
|
||||
* @template Attrs
|
||||
*/
|
||||
export class AttributionManager {
|
||||
export class IdMap {
|
||||
constructor () {
|
||||
/**
|
||||
* @type {Map<number,AttrRanges<Attrs>>}
|
||||
@@ -265,15 +265,15 @@ export class AttributionManager {
|
||||
}
|
||||
}
|
||||
|
||||
export const createAttributionManager = () => new AttributionManager()
|
||||
export const createIdMap = () => new IdMap()
|
||||
|
||||
/**
|
||||
* Remove all ranges from `exclude` from `ds`. The result is a fresh AttributionManager containing all ranges from `idSet` that are not
|
||||
* Remove all ranges from `exclude` from `ds`. The result is a fresh IdMap containing all ranges from `idSet` that are not
|
||||
* in `exclude`.
|
||||
*
|
||||
* @template {AttributionManager<any>} Set
|
||||
* @template {IdMap<any>} Set
|
||||
* @param {Set} set
|
||||
* @param {IdSet | AttributionManager<any>} exclude
|
||||
* @param {IdSet | IdMap<any>} exclude
|
||||
* @return {Set}
|
||||
*/
|
||||
export const diffAttributionManager = _diffSet
|
||||
export const diffIdMap = _diffSet
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
splitItem,
|
||||
iterateStructs,
|
||||
UpdateEncoderV2,
|
||||
AttributionManager,
|
||||
IdMap,
|
||||
AttrRanges,
|
||||
AbstractStruct, DSDecoderV1, DSEncoderV1, DSDecoderV2, DSEncoderV2, Item, GC, StructStore, Transaction, ID // eslint-disable-line
|
||||
} from '../internals.js'
|
||||
@@ -217,16 +217,16 @@ export const insertIntoIdSet = (dest, src) => {
|
||||
* Remove all ranges from `exclude` from `ds`. The result is a fresh IdSet containing all ranges from `idSet` that are not
|
||||
* in `exclude`.
|
||||
*
|
||||
* @template {IdSet | AttributionManager<any>} Set
|
||||
* @template {IdSet | IdMap<any>} Set
|
||||
* @param {Set} set
|
||||
* @param {IdSet | AttributionManager<any>} exclude
|
||||
* @param {IdSet | IdMap<any>} exclude
|
||||
* @return {Set}
|
||||
*/
|
||||
export const _diffSet = (set, exclude) => {
|
||||
/**
|
||||
* @type {Set}
|
||||
*/
|
||||
const res = /** @type {any } */ (set instanceof IdSet ? new IdSet() : new AttributionManager())
|
||||
const res = /** @type {any } */ (set instanceof IdSet ? new IdSet() : new IdMap())
|
||||
const Ranges = set instanceof IdSet ? IdRanges : AttrRanges
|
||||
set.clients.forEach((_setRanges, client) => {
|
||||
/**
|
||||
@@ -288,7 +288,7 @@ export const _diffSet = (set, exclude) => {
|
||||
*
|
||||
* @template {IdSet} Set
|
||||
* @param {Set} set
|
||||
* @param {IdSet | AttributionManager<any>} exclude
|
||||
* @param {IdSet | IdMap<any>} exclude
|
||||
* @return {Set}
|
||||
*/
|
||||
export const diffIdSet = _diffSet
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import * as t from 'lib0/testing'
|
||||
import * as am from '../src/utils/AttributionManager.js'
|
||||
import { compareAttributionManagers, createAttributionManager, ID, createRandomIdSet, createRandomAttributionManager } from './testHelper.js'
|
||||
import * as am from '../src/utils/IdMap.js'
|
||||
import { compareIdmaps, createIdMap, ID, createRandomIdSet, createRandomIdMap } from './testHelper.js'
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @param {Array<[number, number, number, Array<T>]>} ops
|
||||
*/
|
||||
const simpleConstructAttrs = ops => {
|
||||
const attrs = createAttributionManager()
|
||||
const attrs = createIdMap()
|
||||
ops.forEach(op => {
|
||||
attrs.add(op[0], op[1], op[2], op[3])
|
||||
})
|
||||
@@ -20,49 +20,49 @@ const simpleConstructAttrs = ops => {
|
||||
export const testAmMerge = _tc => {
|
||||
const attrs = [42]
|
||||
t.group('filter out empty items (1))', () => {
|
||||
compareAttributionManagers(
|
||||
compareIdmaps(
|
||||
simpleConstructAttrs([[0, 1, 0, attrs]]),
|
||||
simpleConstructAttrs([])
|
||||
)
|
||||
})
|
||||
t.group('filter out empty items (2))', () => {
|
||||
compareAttributionManagers(
|
||||
compareIdmaps(
|
||||
simpleConstructAttrs([[0, 1, 0, attrs], [0, 2, 0, attrs]]),
|
||||
simpleConstructAttrs([])
|
||||
)
|
||||
})
|
||||
t.group('filter out empty items (3 - end))', () => {
|
||||
compareAttributionManagers(
|
||||
compareIdmaps(
|
||||
simpleConstructAttrs([[0, 1, 1, attrs], [0, 2, 0, attrs]]),
|
||||
simpleConstructAttrs([[0, 1, 1, attrs]])
|
||||
)
|
||||
})
|
||||
t.group('filter out empty items (4 - middle))', () => {
|
||||
compareAttributionManagers(
|
||||
compareIdmaps(
|
||||
simpleConstructAttrs([[0, 1, 1, attrs], [0, 2, 0, attrs], [0, 3, 1, attrs]]),
|
||||
simpleConstructAttrs([[0, 1, 1, attrs], [0, 3, 1, attrs]])
|
||||
)
|
||||
})
|
||||
t.group('filter out empty items (5 - beginning))', () => {
|
||||
compareAttributionManagers(
|
||||
compareIdmaps(
|
||||
simpleConstructAttrs([[0, 1, 0, attrs], [0, 2, 1, attrs], [0, 3, 1, attrs]]),
|
||||
simpleConstructAttrs([[0, 2, 1, attrs], [0, 3, 1, attrs]])
|
||||
)
|
||||
})
|
||||
t.group('merge of overlapping id ranges', () => {
|
||||
compareAttributionManagers(
|
||||
compareIdmaps(
|
||||
simpleConstructAttrs([[0, 1, 2, attrs], [0, 0, 2, attrs]]),
|
||||
simpleConstructAttrs([[0, 0, 3, attrs]])
|
||||
)
|
||||
})
|
||||
t.group('construct without hole', () => {
|
||||
compareAttributionManagers(
|
||||
compareIdmaps(
|
||||
simpleConstructAttrs([[0, 1, 2, attrs], [0, 3, 1, attrs]]),
|
||||
simpleConstructAttrs([[0, 1, 3, attrs]])
|
||||
)
|
||||
})
|
||||
t.group('no merge of overlapping id ranges with different attributes', () => {
|
||||
compareAttributionManagers(
|
||||
compareIdmaps(
|
||||
simpleConstructAttrs([[0, 1, 2, [1]], [0, 0, 2, [2]]]),
|
||||
simpleConstructAttrs([[0, 0, 1, [2]], [0, 1, 1, [1, 2]], [0, 2, 1, [1]]])
|
||||
)
|
||||
@@ -72,20 +72,20 @@ export const testAmMerge = _tc => {
|
||||
/**
|
||||
* @param {t.TestCase} tc
|
||||
*/
|
||||
export const testRepeatMergingMultipleAttrManagers = tc => {
|
||||
export const testRepeatMergingMultipleIdMaps = tc => {
|
||||
const clients = 4
|
||||
const clockRange = 5
|
||||
/**
|
||||
* @type {Array<am.AttributionManager<number>>}
|
||||
* @type {Array<am.IdMap<number>>}
|
||||
*/
|
||||
const sets = []
|
||||
for (let i = 0; i < 3; i++) {
|
||||
sets.push(createRandomAttributionManager(tc.prng, clients, clockRange, [1, 2, 3]))
|
||||
sets.push(createRandomIdMap(tc.prng, clients, clockRange, [1, 2, 3]))
|
||||
}
|
||||
const merged = am.mergeAttributionManagers(sets)
|
||||
const mergedReverse = am.mergeAttributionManagers(sets.reverse())
|
||||
compareAttributionManagers(merged, mergedReverse)
|
||||
const composed = am.createAttributionManager()
|
||||
const merged = am.mergeIdMaps(sets)
|
||||
const mergedReverse = am.mergeIdMaps(sets.reverse())
|
||||
compareIdmaps(merged, mergedReverse)
|
||||
const composed = am.createIdMap()
|
||||
for (let iclient = 0; iclient < clients; iclient++) {
|
||||
for (let iclock = 0; iclock < clockRange + 42; iclock++) {
|
||||
const mergedHas = merged.has(new ID(iclient, iclock))
|
||||
@@ -99,7 +99,7 @@ export const testRepeatMergingMultipleAttrManagers = tc => {
|
||||
}
|
||||
}
|
||||
}
|
||||
compareAttributionManagers(merged, composed)
|
||||
compareIdmaps(merged, composed)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,12 +109,12 @@ export const testRepeatRandomDiffing = tc => {
|
||||
const clients = 4
|
||||
const clockRange = 100
|
||||
const attrs = [1, 2, 3]
|
||||
const ds1 = createRandomAttributionManager(tc.prng, clients, clockRange, attrs)
|
||||
const ds2 = createRandomAttributionManager(tc.prng, clients, clockRange, attrs)
|
||||
const merged = am.mergeAttributionManagers([ds1, ds2])
|
||||
const e1 = am.diffAttributionManager(ds1, ds2)
|
||||
const e2 = am.diffAttributionManager(merged, ds2)
|
||||
compareAttributionManagers(e1, e2)
|
||||
const ds1 = createRandomIdMap(tc.prng, clients, clockRange, attrs)
|
||||
const ds2 = createRandomIdMap(tc.prng, clients, clockRange, attrs)
|
||||
const merged = am.mergeIdMaps([ds1, ds2])
|
||||
const e1 = am.diffIdMap(ds1, ds2)
|
||||
const e2 = am.diffIdMap(merged, ds2)
|
||||
compareIdmaps(e1, e2)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -124,13 +124,13 @@ export const testRepeatRandomDiffing2 = tc => {
|
||||
const clients = 4
|
||||
const clockRange = 100
|
||||
const attrs = [1, 2, 3]
|
||||
const am1 = createRandomAttributionManager(tc.prng, clients, clockRange, attrs)
|
||||
const am2 = createRandomAttributionManager(tc.prng, clients, clockRange, attrs)
|
||||
const am1 = createRandomIdMap(tc.prng, clients, clockRange, attrs)
|
||||
const am2 = createRandomIdMap(tc.prng, clients, clockRange, attrs)
|
||||
const idsExclude = createRandomIdSet(tc.prng, clients, clockRange)
|
||||
const merged = am.mergeAttributionManagers([am1, am2])
|
||||
const mergedExcluded = am.diffAttributionManager(merged, idsExclude)
|
||||
const e1 = am.diffAttributionManager(am1, idsExclude)
|
||||
const e2 = am.diffAttributionManager(am2, idsExclude)
|
||||
const excludedMerged = am.mergeAttributionManagers([e1, e2])
|
||||
compareAttributionManagers(mergedExcluded, excludedMerged)
|
||||
const merged = am.mergeIdMaps([am1, am2])
|
||||
const mergedExcluded = am.diffIdMap(merged, idsExclude)
|
||||
const e1 = am.diffIdMap(am1, idsExclude)
|
||||
const e2 = am.diffIdMap(am2, idsExclude)
|
||||
const excludedMerged = am.mergeIdMaps([e1, e2])
|
||||
compareIdmaps(mergedExcluded, excludedMerged)
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import * as updates from './updates.tests.js'
|
||||
import * as relativePositions from './relativePositions.tests.js'
|
||||
import * as delta from './delta.tests.js'
|
||||
import * as idset from './IdSet.tests.js'
|
||||
import * as attributionManager from './AttributionManager.tests.js'
|
||||
import * as idmap from './IdMap.tests.js'
|
||||
|
||||
import { runTests } from 'lib0/testing'
|
||||
import { isBrowser, isNode } from 'lib0/environment'
|
||||
@@ -24,7 +24,7 @@ if (isBrowser) {
|
||||
}
|
||||
|
||||
const tests = {
|
||||
doc, map, array, text, xml, encoding, undoredo, compatibility, snapshot, updates, relativePositions, delta, idset, attributionManager
|
||||
doc, map, array, text, xml, encoding, undoredo, compatibility, snapshot, updates, relativePositions, delta, idset, idmap
|
||||
}
|
||||
|
||||
const run = async () => {
|
||||
|
||||
@@ -8,7 +8,7 @@ import * as map from 'lib0/map'
|
||||
import * as Y from '../src/index.js'
|
||||
import * as math from 'lib0/math'
|
||||
import {
|
||||
amAttrsEqual, createIdSet, createAttributionManager, addToIdSet
|
||||
idmapAttrsEqual, createIdSet, createIdMap, addToIdSet
|
||||
} from '../src/internals.js'
|
||||
|
||||
export * from '../src/index.js'
|
||||
@@ -329,10 +329,10 @@ export const compareIdSets = (idSet1, idSet2) => {
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @param {Y.AttributionManager<T>} am1
|
||||
* @param {Y.AttributionManager<T>} am2
|
||||
* @param {Y.IdMap<T>} am1
|
||||
* @param {Y.IdMap<T>} am2
|
||||
*/
|
||||
export const compareAttributionManagers = (am1, am2) => {
|
||||
export const compareIdmaps = (am1, am2) => {
|
||||
if (am1.clients.size !== am2.clients.size) return false
|
||||
for (const [client, _items1] of am1.clients.entries()) {
|
||||
const items1 = _items1.getIds()
|
||||
@@ -340,8 +340,8 @@ export const compareAttributionManagers = (am1, am2) => {
|
||||
t.assert(items2 !== undefined && items1.length === items2.length)
|
||||
for (let i = 0; i < items1.length; i++) {
|
||||
const di1 = items1[i]
|
||||
const di2 = /** @type {Array<import('../src/utils/AttributionManager.js').AttrRange<T>>} */ (items2)[i]
|
||||
t.assert(di1.clock === di2.clock && di1.len === di2.len && amAttrsEqual(di1.attrs, di2.attrs))
|
||||
const di2 = /** @type {Array<import('../src/utils/IdMap.js').AttrRange<T>>} */ (items2)[i]
|
||||
t.assert(di1.clock === di2.clock && di1.len === di2.len && idmapAttrsEqual(di1.attrs, di2.attrs))
|
||||
}
|
||||
}
|
||||
return true
|
||||
@@ -374,12 +374,12 @@ export const createRandomIdSet = (gen, clients, clockRange) => {
|
||||
* @param {number} clients
|
||||
* @param {number} clockRange (max clock - exclusive - by each client)
|
||||
* @param {Array<T>} attrChoices (max clock - exclusive - by each client)
|
||||
* @return {Y.AttributionManager<T>}
|
||||
* @return {Y.IdMap<T>}
|
||||
*/
|
||||
export const createRandomAttributionManager = (gen, clients, clockRange, attrChoices) => {
|
||||
export const createRandomIdMap = (gen, clients, clockRange, attrChoices) => {
|
||||
const maxOpLen = 5
|
||||
const numOfOps = math.ceil((clients * clockRange) / maxOpLen)
|
||||
const attrMngr = createAttributionManager()
|
||||
const idMap = createIdMap()
|
||||
for (let i = 0; i < numOfOps; i++) {
|
||||
const client = prng.uint32(gen, 0, clients - 1)
|
||||
const clockStart = prng.uint32(gen, 0, clockRange)
|
||||
@@ -392,9 +392,9 @@ export const createRandomAttributionManager = (gen, clients, clockRange, attrCho
|
||||
attrs.push(a)
|
||||
}
|
||||
}
|
||||
attrMngr.add(client, clockStart, len, attrs)
|
||||
idMap.add(client, clockStart, len, attrs)
|
||||
}
|
||||
return attrMngr
|
||||
return idMap
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user