Skip to content

Commit

Permalink
Revise the representation of addRight ops (a skin-deep change; a lot …
Browse files Browse the repository at this point in the history
…of stuff was renamed).
  • Loading branch information
jorendorff committed Apr 13, 2016
1 parent 9cb8707 commit 8615e65
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 36 deletions.
71 changes: 36 additions & 35 deletions lib/rga.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function RGA(id, history, queue) {
throw new TypeError("RGA constructor: first argument is not a valid id");
this._idForLogging = RGA._nextIdForLogging++;
this.id = id;
this.left = {next: undefined, timestamp: -1, atom: undefined, removed: false};
this.left = {next: undefined, timestamp: -1, chr: undefined, removed: false};
this._index = new Map([[this.left.timestamp, this.left]]);
this._nextTimestamp = id;
this._subscribers = [];
Expand Down Expand Up @@ -68,8 +68,9 @@ RGA.prototype = {
while (curr !== undefined) {
h.push({
type: "addRight",
t: prev.timestamp,
w: {timestamp: curr.timestamp, atom: curr.atom}
prev: prev.timestamp,
t: curr.timestamp,
chr: curr.chr
});
if (curr.removed)
h.push({type: "remove", t: curr.timestamp});
Expand All @@ -79,42 +80,43 @@ RGA.prototype = {
return h;
},

addRight: function (t, a) {
var pred = this._index.get(t);
if (pred === undefined)
addRight: function (prev, chr) {
var target = this._index.get(prev);
if (target === undefined)
throw new Error("insertion point is not in the array");
if (pred.removed)
if (target.removed)
throw new Error("insertion point is removed from the array");

var node = {timestamp: this._timestamp(), atom: a};
this.downstream(this.downstream, {type: "addRight", t: t, w: node});
return node.timestamp;
var t = this._timestamp();
this.downstream(this.downstream, {
type: "addRight", prev: prev, t: t, chr: chr
});
return t;
},

_downstream_addRight: function (op) {
// Any future timestamps we generate must be after timestamps we've
// observed.
if (op.w.timestamp >= this._nextTimestamp) {
var t = (op.w.timestamp >>> MAX_REPLICA_ID_BITS) + 1;
if (op.t >= this._nextTimestamp) {
var t = (op.t >>> MAX_REPLICA_ID_BITS) + 1;
this._nextTimestamp = (t << MAX_REPLICA_ID_BITS) + this.id;
}

var w = op.w;
var pred = this._index.get(op.t);
var pred = this._index.get(op.prev);
if (pred === undefined)
throw new Error("downstream: can't add next to unknown element!");
while (pred.next && w.timestamp < pred.next.timestamp)
while (pred.next && op.t < pred.next.timestamp)
pred = pred.next;

// Splice a new node into the linked list.
var node = {
next: pred.next,
timestamp: w.timestamp,
atom: w.atom,
timestamp: op.t,
chr: op.chr,
removed: false
};
pred.next = node;
this._index.set(w.timestamp, node);
this._index.set(op.t, node);
},

_lookup: function (t) {
Expand All @@ -139,7 +141,7 @@ RGA.prototype = {
var s = "";
for (var node = this.left.next; node; node = node.next) {
if (!node.removed)
s += node.atom;
s += node.chr;
}
return s;
},
Expand Down Expand Up @@ -370,7 +372,7 @@ Object.assign(RGA.AceEditorRGA.prototype, {
var r = 0, c = 0;
for (var node = this.left.next; node != target; node = node.next) {
if (!node.removed) {
if (node.atom === "\n") {
if (node.chr === "\n") {
r++;
c = 0;
} else {
Expand All @@ -382,16 +384,16 @@ Object.assign(RGA.AceEditorRGA.prototype, {
},

// Return the coordinates of a hypothetical new character, if you inserted it
// with timestamp `wt`, after the character with timestamp `t`.
getRowColumnAfter: function (t, wt) {
var target = this._index.get(t);
// with timestamp `t`, after the character with timestamp `prev`.
getRowColumnAfter: function (prev, t) {
var target = this._index.get(prev);
if (target === undefined)
throw new Error("timestamp not present in document");

var r = 0, c = -1; // c will be incremented to zero in the first pass through the loop
function advance(node) {
if (!node.removed) {
if (node.atom === "\n") {
if (node.chr === "\n") {
r++;
c = 0;
} else {
Expand All @@ -405,7 +407,7 @@ Object.assign(RGA.AceEditorRGA.prototype, {
if (node === target)
break;
}
while (node.next && wt < node.next.timestamp) {
while (node.next && t < node.next.timestamp) {
node = node.next;
advance(node);
}
Expand Down Expand Up @@ -448,22 +450,21 @@ Object.assign(RGA.AceEditorRGA.prototype, {
if (!node.removed) {
lastNode = node;
j++;
//this._log(" - removing character:", node.atom);
//this._log(" - removing character:", node.chr);
this._downstream(source, {type: "remove", t: node.timestamp});
}
node = next;
}
} else if ("insert" in op) {
var t = lastNode.timestamp;
var prev = lastNode.timestamp;
var str = op.insert;
for (var j = 0; j < str.length; j++) {
//this._log(" - inserting character:", str[j]);
var tnext = this._timestamp();
var next = {atom: str[j], timestamp: tnext};
this._downstream(source, {type: "addRight", t: t, w: next});
t = tnext;
this._downstream(source, {type: "addRight", prev: prev, t: tnext, chr: str[j]});
prev = tnext;
}
lastNode = this._index.get(t);
lastNode = this._index.get(prev);
node = lastNode.next;
}
}
Expand Down Expand Up @@ -503,15 +504,15 @@ Object.assign(RGA.AceEditorRGA.prototype, {
var session = this.editor.getSession();
switch (op.type) {
case "addRight":
if (this._index.has(op.w.timestamp)) {
if (this._index.has(op.t)) {
// This character was already added.
throw new Error("bug - message delivered twice to " + this.id + ": ", JSON.stringify(op));
}

var loc = this.getRowColumnAfter(op.t, op.w.timestamp);
//this._log("inserting character", op.w.atom, "at", loc);
var loc = this.getRowColumnAfter(op.prev, op.t);
//this._log("inserting character", op.chr, "at", loc);
this._withEditorCallbacksDisabled(function () {
session.insert(loc, op.w.atom);
session.insert(loc, op.chr);
});
break;

Expand Down
2 changes: 1 addition & 1 deletion test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ describe("RGA", () => {

a.deliver("downstream", {
type: "addRight",
w: {atom: "Q"}
chr: "Q"
});
queue.drain();
assert.strictEqual(q.text(), "Q");
Expand Down

0 comments on commit 8615e65

Please sign in to comment.