Skip to content

Commit

Permalink
Use TreeRangeStruct to represent tree selection (#561)
Browse files Browse the repository at this point in the history
* Use TreeRangeStruct to represent tree selection

* Rename getStructure to toStructure

* Remove using getStructureAsString for purposes other than testing

* Rename methods that convert to XX for testing purposes to `toTestXX`

* Add toIDString

* Expose CRDTTreePosStruct, TreeRangeStruct and TimeTicketStruct

---------

Co-authored-by: Hackerwins <[email protected]>
  • Loading branch information
chacha912 and hackerwins authored Jul 5, 2023
1 parent d5babaa commit 3a59d69
Show file tree
Hide file tree
Showing 37 changed files with 399 additions and 308 deletions.
2 changes: 1 addition & 1 deletion public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
function displayLog(doc, codemirror) {
logHolder.innerText = doc.toJSON();

textLogHolder.innerText = doc.getRoot().content.getStructureAsString();
textLogHolder.innerText = doc.getRoot().content.toTestString();
}

function displayPeers(peers, myClientID) {
Expand Down
34 changes: 8 additions & 26 deletions public/prosemirror.html
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ <h2>Yorkie.RGASplit</h2>
*/
function updateSelectionLayer(view, tree, actor) {
const { layer, fromPos, toPos } = selectionMap.get(actor);
const [fromIndex, toIndex] = tree.rangeToIndex([fromPos, toPos]);
const [fromIndex, toIndex] = tree.toIndexRange([fromPos, toPos]);
const coords = view.coordsAtPos(Math.min(fromIndex, toIndex));

layer.style.left = `${coords.left - 10}px`;
Expand Down Expand Up @@ -277,19 +277,6 @@ <h2>Yorkie.RGASplit</h2>
return true;
}

function encodeRange(tree, from, to) {
const range = tree.createRange(from, to);
const fromBytes = yorkie.converter.treePosToBytes(range[0]);
const toBytes = yorkie.converter.treePosToBytes(range[1]);
return [fromBytes, toBytes];
}

function decodeRange(fromBytes, toBytes) {
const from = yorkie.converter.bytesToTreePos(fromBytes);
const to = yorkie.converter.bytesToTreePos(toBytes);
return [from, to];
}

/**
* main is the entry point of the example.
*/
Expand Down Expand Up @@ -337,11 +324,10 @@ <h2>Yorkie.RGASplit</h2>
});

doc.update((root) => {
root.selection = encodeRange(
root.tree,
root.selection = root.tree.toPosRange([
transaction.curSelection.from,
transaction.curSelection.to,
);
]);
});
printLog();
return;
Expand Down Expand Up @@ -395,11 +381,10 @@ <h2>Yorkie.RGASplit</h2>
}
}

root.selection = encodeRange(
root.tree,
root.selection = root.tree.toPosRange([
transaction.curSelection.from,
transaction.curSelection.to,
);
]);
});
printLog();
},
Expand All @@ -423,12 +408,11 @@ <h2>Yorkie.RGASplit</h2>
op.key === 'selection'
) {
const selection = doc.getRoot().selection;
const range = decodeRange(selection[0], selection[1]);
displayRemoteSelection(
view,
root.tree,
range[0],
range[1],
selection[0],
selection[1],
actor,
);
}
Expand Down Expand Up @@ -541,9 +525,7 @@ <h2>Yorkie.RGASplit</h2>
let node = head;
while (node) {
const nodeType = node.type;
const pos = `${node.pos.createdAt.getStructureAsString()}-${
node.pos.offset
}`;
const pos = `${node.pos.createdAt.toTestString()}-${node.pos.offset}`;
if (nodeType === 'text') {
arr.push({
type: nodeType,
Expand Down
2 changes: 1 addition & 1 deletion public/quill.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

function displayLog(elem, textElem, doc) {
elem.innerText = doc.toJSON();
textElem.innerText = doc.getRoot().content.getStructureAsString();
textElem.innerText = doc.getRoot().content.toTestString();
}

function toDeltaOperation(textValue) {
Expand Down
32 changes: 6 additions & 26 deletions src/api/converter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,8 +256,8 @@ function toTextNodePos(pos: RGATreeSplitNodePos): PbTextNodePos {
*/
function toTreePos(pos: CRDTTreePos): PbTreePos {
const pbTreePos = new PbTreePos();
pbTreePos.setCreatedAt(toTimeTicket(pos.createdAt));
pbTreePos.setOffset(pos.offset);
pbTreePos.setCreatedAt(toTimeTicket(pos.getCreatedAt()));
pbTreePos.setOffset(pos.getOffset());
return pbTreePos;
}

Expand Down Expand Up @@ -831,10 +831,10 @@ function fromTextNode(pbTextNode: PbTextNode): RGATreeSplitNode<CRDTTextValue> {
* `fromTreePos` converts the given Protobuf format to model format.
*/
function fromTreePos(pbTreePos: PbTreePos): CRDTTreePos {
return {
createdAt: fromTimeTicket(pbTreePos.getCreatedAt())!,
offset: pbTreePos.getOffset(),
};
return CRDTTreePos.of(
fromTimeTicket(pbTreePos.getCreatedAt())!,
pbTreePos.getOffset(),
);
}

/**
Expand Down Expand Up @@ -1211,24 +1211,6 @@ function treeToBytes(tree: CRDTTree): Uint8Array {
return toTree(tree).serializeBinary();
}

/**
* `treePosToBytes` converts the given CRDTTreePos to byte array.
*/
function treePosToBytes(pos: CRDTTreePos): Uint8Array {
return toTreePos(pos).serializeBinary();
}

/**
* `bytesToTreePos` creates an CRDTTreePos from the given bytes.
*/
function bytesToTreePos(bytes: Uint8Array): CRDTTreePos {
if (!bytes) {
throw new Error('bytes is empty');
}
const pbTreePos = PbTreePos.deserializeBinary(bytes);
return fromTreePos(pbTreePos);
}

/**
* `bytesToHex` creates an hex string from the given byte array.
*/
Expand Down Expand Up @@ -1279,6 +1261,4 @@ export const converter = {
bytesToObject,
toHexString,
toUint8Array,
bytesToTreePos,
treePosToBytes,
};
2 changes: 1 addition & 1 deletion src/client/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1171,7 +1171,7 @@ export class Client<P = Indexable> implements Observable<ClientEvent<P>> {
logger.info(
`[PP] c:"${this.getKey()}" sync d:"${docKey}", push:${localSize} pull:${remoteSize} cp:${respPack
.getCheckpoint()
.getStructureAsString()}`,
.toTestString()}`,
);
},
)
Expand Down
6 changes: 3 additions & 3 deletions src/document/change/change.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,11 @@ export class Change {
}

/**
* `getStructureAsString` returns a string containing the meta data of this change.
* `toTestString` returns a string containing the meta data of this change.
*/
public getStructureAsString(): string {
public toTestString(): string {
return `${this.operations
.map((operation) => operation.getStructureAsString())
.map((operation) => operation.toTestString())
.join(',')}`;
}
}
4 changes: 2 additions & 2 deletions src/document/change/change_id.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,9 @@ export class ChangeID {
}

/**
* `getStructureAsString` returns a string containing the meta data of this ID.
* `toTestString` returns a string containing the meta data of this ID.
*/
public getStructureAsString(): string {
public toTestString(): string {
if (!this.actor) {
return `${this.lamport.toString()}:nil:${this.clientSeq}`;
}
Expand Down
4 changes: 2 additions & 2 deletions src/document/change/checkpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,10 @@ export class Checkpoint {
}

/**
* `getStructureAsString` returns a string containing the meta data of this
* `toTestString` returns a string containing the meta data of this
* checkpoint.
*/
public getStructureAsString(): string {
public toTestString(): string {
return `serverSeq=${this.serverSeq}, clientSeq=${this.clientSeq}`;
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/document/crdt/array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,11 +163,11 @@ export class CRDTArray extends CRDTContainer {
}

/**
* `getStructureAsString` returns a String containing the meta data of this value
* `toTestString` returns a String containing the meta data of this value
* for debugging purpose.
*/
public getStructureAsString(): string {
return this.elements.getStructureAsString();
public toTestString(): string {
return this.elements.toTestString();
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/document/crdt/rga_tree_list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -387,10 +387,10 @@ export class RGATreeList {
}

/**
* `getStructureAsString` returns a String containing the meta data of the node id
* `toTestString` returns a String containing the meta data of the node id
* for debugging purpose.
*/
public getStructureAsString(): string {
public toTestString(): string {
const json = [];

for (const node of this) {
Expand Down
61 changes: 44 additions & 17 deletions src/document/crdt/rga_tree_split.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
InitialTimeTicket,
MaxTimeTicket,
TimeTicket,
TimeTicketStruct,
} from '@yorkie-js-sdk/src/document/time/ticket';

export interface ValueChange<T> {
Expand All @@ -37,6 +38,15 @@ interface RGATreeSplitValue {
substring(indexStart: number, indexEnd?: number): RGATreeSplitValue;
}

/**
* `RGATreeSplitNodeIDStruct` is a structure represents the meta data of the node id.
* It is used to serialize and deserialize the node id.
*/
type RGATreeSplitNodeIDStruct = {
createdAt: TimeTicketStruct;
offset: number;
};

/**
* `RGATreeSplitNodeID` is an ID of RGATreeSplitNode.
*/
Expand Down Expand Up @@ -95,11 +105,28 @@ export class RGATreeSplitNodeID {
}

/**
* `getStructureAsString` returns a String containing
* `toStructure` returns the structure of this node id.
*/
public toStructure(): RGATreeSplitNodeIDStruct {
return {
createdAt: this.createdAt.toStructure(),
offset: this.offset,
};
}

/**
* `toTestString` returns a String containing
* the meta data of the node id for debugging purpose.
*/
public getStructureAsString(): string {
return `${this.createdAt.getStructureAsString()}:${this.offset}`;
public toTestString(): string {
return `${this.createdAt.toTestString()}:${this.offset}`;
}

/**
* `toIDString` returns a string that can be used as an ID for this node id.
*/
public toIDString(): string {
return `${this.createdAt.toIDString()}:${this.offset}`;
}
}

Expand Down Expand Up @@ -152,11 +179,11 @@ export class RGATreeSplitNodePos {
}

/**
*`getStructureAsString` returns a String containing
*`toTestString` returns a String containing
* the meta data of the position for debugging purpose.
*/
public getStructureAsString(): string {
return `${this.id.getStructureAsString()}:${this.relativeOffset}`;
public toTestString(): string {
return `${this.id.toTestString()}:${this.relativeOffset}`;
}

/**
Expand Down Expand Up @@ -405,11 +432,11 @@ export class RGATreeSplitNode<
}

/**
* `getStructureAsString` returns a String containing
* `toTestString` returns a String containing
* the meta data of the node for debugging purpose.
*/
public getStructureAsString(): string {
return `${this.id.getStructureAsString()} ${this.value ? this.value : ''}`;
public toTestString(): string {
return `${this.id.toTestString()} ${this.value ? this.value : ''}`;
}

private splitValue(offset: number): T {
Expand Down Expand Up @@ -547,7 +574,7 @@ export class RGATreeSplit<T extends RGATreeSplitValue> {
: this.findFloorNode(absoluteID);
if (!node) {
logger.fatal(
`the node of the given id should be found: ${absoluteID.getStructureAsString()}`,
`the node of the given id should be found: ${absoluteID.toTestString()}`,
);
}
const index = this.treeByIndex.indexOf(node!);
Expand Down Expand Up @@ -635,18 +662,18 @@ export class RGATreeSplit<T extends RGATreeSplitValue> {
}

/**
* `getStructureAsString` returns a String containing the meta data of the node
* `toTestString` returns a String containing the meta data of the node
* for debugging purpose.
*/
public getStructureAsString(): string {
public toTestString(): string {
const result = [];

let node: RGATreeSplitNode<T> | undefined = this.head;
while (node) {
if (node.isRemoved()) {
result.push(`{${node.getStructureAsString()}}`);
result.push(`{${node.toTestString()}}`);
} else {
result.push(`[${node.getStructureAsString()}]`);
result.push(`[${node.toTestString()}]`);
}

node = node.getNext();
Expand Down Expand Up @@ -700,7 +727,7 @@ export class RGATreeSplit<T extends RGATreeSplitValue> {
let node = this.findFloorNode(id);
if (!node) {
logger.fatal(
`the node of the given id should be found: ${id.getStructureAsString()}`,
`the node of the given id should be found: ${id.toTestString()}`,
);
}

Expand Down Expand Up @@ -810,7 +837,7 @@ export class RGATreeSplit<T extends RGATreeSplitValue> {
) {
createdAtMapByActor.set(actorID, node.getID().getCreatedAt());
}
removedNodeMap.set(node.getID().getStructureAsString(), node);
removedNodeMap.set(node.getID().toIDString(), node);
node.remove(editedAt);
}
// Finally remove index nodes of tombstones.
Expand Down Expand Up @@ -937,7 +964,7 @@ export class RGATreeSplit<T extends RGATreeSplitValue> {
this.treeByIndex.delete(node);
this.purge(node);
this.treeByID.remove(node.getID());
this.removedNodeMap.delete(node.getID().getStructureAsString());
this.removedNodeMap.delete(node.getID().toIDString());
count++;
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/document/crdt/text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -379,11 +379,11 @@ export class CRDTText<A extends Indexable = Indexable> extends CRDTGCElement {
}

/**
* `getStructureAsString` returns a String containing the meta data of this value
* `toTestString` returns a String containing the meta data of this value
* for debugging purpose.
*/
public getStructureAsString(): string {
return this.rgaTreeSplit.getStructureAsString();
public toTestString(): string {
return this.rgaTreeSplit.toTestString();
}

/**
Expand Down
Loading

0 comments on commit 3a59d69

Please sign in to comment.