50 Composite operations on a text field
Atomic operation
An atomic operation is associated with particular (s,t) - i.e. an opid. Although it can represent arbitrary changes to objects in the Universal Tree (UT), in practise the changes tend to be rather minor.
// Identifies atomic operation op(s,t)
struct Opid
{
SiteId s;
int t;
};
Composite operation
A composite operation or delta is associated with a set of atomic operations bounded by a pair of causally valid vector times v1,v2. The delta corresponds to the operations in X(v2)\X(v1), which we denote as [v1,v2).
All the changes made on a working set relative to the state associated with the base vector time are recorded in a delta for certain [v1,v2). We assume v1 = {} - i.e. we assume that the vector time is reset to empty at the base vector time associated with a certain state recorded in a repository.
Composite operations on a text field
Definition: Let a composite operation on a text field be represented by the triple (I,D,B) where:
- I is a linear list of non-overlapping insertion intervals, expressed in post-insertion q-coordinates
// Insertion of n characters at position q with temporal index u by operation op(s,t) struct InsertionInterval { Opid opid; int q, n, u; }; - D is a linear list of non-overlapping deletion intervals, expressed in post-insertion q-coordinates
// Deletion of n characters at position q by operation op(s,t) struct DeletionInterval { Opid opid; int q,n; }; - B is the string of characters corrresponding to I\D
Conceptually the deletes are applied after the inserts (indeed D can delete some or all of the characters inserted by I). Both I and D are recorded in post-insertion q-coords.
Mapping from q to p coordinates
The recorded deletions serve the purpose of recording the mapping between p and q coordinates (in previous implementations that was recorded explicitly in the PtoQ map).
Let |S| denote the cardinality of set S. If we interpret the deletion intervals D as a subset of the integers - i.e. the set of q-positions which are tombstones, then we can define the function which maps q to p as follows:
D.getp(q) = q - |[0,q) ⋂ D|
In algorithms where we process q-positions of intervals from left to right, Monotone increasing extents on interval set provides an efficient basis for calculating the cardinality of [0,q) ⋂ D.
Taking an RFactor
Let
(I',D',B') = Rf(I,D,B,v)
be the RFactor of (I,D,B) with respect to vector time v.
Let's write this as:
I' = Rf_i(I,v)
D' = Rf_d(D,v)
B' = Rf_b(I,D,B,v)
The q-coordinates of both insertions and deletions are unchanged in an RFactor - because both are expressed in post-insertion coords.
I' = Rf_i(I,v) simply involves picking intervals in I outside X(v). No adjustments to the q-positions are required. Similarly for D' = Rf_d(D,v).
field_RFactor(B,I\D,v) assumes B is a buffer of characters corresponding to I\D. So it can be assumed B.size() == (I/D).extent(). This function calculates B' which corresponds to I'\D where I' = insertion_RFactor(I,v).
Taking an LFactor
insertion_Lfactor(I,v) involves picking the intervals inside X(v) and applying a negative shift according to the total extent of the intervals outside X(v) to the left of that interval.