bool swap (modification& m1, modification& m2) { path rp1= root (m1); path rp2= root (m2); if (is_nil (rp1)) switch (m1->k) { case MOD_ASSIGN: { if (m1 == m2) return true; if (!is_nil (rp2) || m2->k != MOD_INSERT_NODE) return false; modification aux= m2; m2= modification (m1->k, path (m2->p->item, m1->p), m1->t); m1= aux; return true; } case MOD_INSERT: { if (is_nil (m2->p)) return false; int b= m1->p->item; int e= b + insert_length (m1->t); if (m2->p->item >= b && m2->p->item < e) if (!is_nil (root (m2)) || m2->p->item != b || m2->k != MOD_INSERT) if (!is_nil (root (m2)) || m2->k != MOD_INSERT_NODE) return false; return swap1 (m1, m2, b, e-b); } case MOD_REMOVE: { if (is_nil (m2->p)) return false; int i= m1->p->item; int d= m1->p->next->item; return swap1 (m1, m2, i, -d); } case MOD_SPLIT: { if (is_nil (m2->p)) return false; int i= m1->p->item; if (m2->p->item == i || m2->p->item == i+1) if (!is_nil (root (m2)) || m2->p->item != i || m2->k != MOD_INSERT) if (!is_nil (root (m2)) || m2->k != MOD_INSERT_NODE) return false; return swap1 (m1, m2, i, 1); } case MOD_JOIN: { if (is_nil (m2->p)) return false; int i= m1->p->item; if (m2->p->item == i) if (!is_nil (root (m2)) || m2->k != MOD_INSERT) return false; return swap1 (m1, m2, i, -1); } case MOD_ASSIGN_NODE: { if (!is_nil (root (m2))) return swap_basic (m1, m2); if (m1 == m2) return true; if (!is_nil (rp2) || m2->k != MOD_INSERT_NODE) return false; modification aux= m2; m2= modification (m1->k, path (m2->p->item, m1->p), m1->t); m1= aux; return true; } case MOD_INSERT_NODE: { if (is_nil (root (m2))) return false; if (m2->p->item != m1->p->item) return false; modification aux= m1; m1= modification (m2->k, m2->p->next, m2->t); if (m2->k != MOD_INSERT_NODE || !is_nil (root (m1))) m2= aux; else m2= modification (aux->k, path (m1->p->item, aux->p), aux->t); return true; } case MOD_REMOVE_NODE: { modification aux= m1; m1= modification (m2->k, path (m1->p->item, m2->p), m2->t); m2= aux; return true; } case MOD_SET_CURSOR: { if (!is_nil (rp2) || m2->k == MOD_JOIN || m2->k == MOD_SPLIT || m2->k == MOD_ASSIGN_NODE) return swap_basic (m1, m2); return false; } } else if (is_nil (rp2)) switch (m2->k) { case MOD_ASSIGN: return false; case MOD_INSERT: { int b= m2->p->item; int e= b + insert_length (m2->t); return swap2 (m1, m2, b, e-b); } case MOD_REMOVE: { int b= m2->p->item; int e= b + m2->p->next->item; if (m1->p->item >= b && m1->p->item < e) return false; return swap2 (m1, m2, b, b-e); } case MOD_SPLIT: { int i= m2->p->item; if (m1->p->item == i) return false; return swap2 (m1, m2, i, 1); } case MOD_JOIN: { int i= m2->p->item; if (m1->p->item == i || m1->p->item == i+1) return false; return swap2 (m1, m2, i, -1); } case MOD_ASSIGN_NODE: return swap_basic (m1, m2); case MOD_INSERT_NODE: { modification aux= m2; m2= modification (m1->k, path (m2->p->item, m1->p), m1->t); m1= aux; return true; } case MOD_REMOVE_NODE: { if (m1->p->item != m2->p->item) return false; modification aux= m2; m2= modification (m1->k, m1->p->next, m1->t); m1= aux; return true; } case MOD_SET_CURSOR: { if (!is_nil (rp1) || m1->k == MOD_JOIN || m1->k == MOD_SPLIT || m1->k == MOD_ASSIGN_NODE) return swap_basic (m1, m2); return false; } } else if (rp1->item == rp2->item) { path h (rp1->item); modification s1= m1 / h; modification s2= m2 / h; bool r= swap (s1, s2); m1= h * s1; m2= h * s2; return r; } else return swap_basic (m1, m2); FAILED ("unexpected situation"); }
bool swap (patch& p1, patch& p2, double a1, double a2) { if (is_nil (p1) || is_nil (p2)) return false; if (get_type (p1) == PATCH_BRANCH) return false; if (get_type (p2) == PATCH_BRANCH) return false; if (get_type (p1) == PATCH_COMPOUND) { int n= N(p1); array<patch> a (n); for (int i=0; i<n; i++) a[i]= p1[i]; for (int i=n-1; i>=0; i--) { if (!swap (a[i], p2, a1, a2)) return false; swap_basic (a[i], p2); } p1= p2; p2= patch (a); return true; } if (get_type (p2) == PATCH_COMPOUND) { int n= N(p2); array<patch> a (n); for (int i=0; i<n; i++) a[i]= p2[i]; for (int i=0; i<n; i++) { if (!swap (p1, a[i], a1, a2)) return false; swap_basic (p1, a[i]); } p2= p1; p1= patch (a); return true; } if (get_type (p1) == PATCH_AUTHOR) { patch s= p1[0]; bool r= swap (s, p2, get_author (p1), a2); p2= patch (get_author (p1), p2); p1= s; return r; } if (get_type (p2) == PATCH_AUTHOR) { patch s= p2[0]; bool r= swap (p1, s, a1, get_author (p2)); p1= patch (get_author (p2), p1); p2= s; return r; } if (get_type (p1) == PATCH_BIRTH) { if (get_author (p1) == a2) return false; return swap_basic (p1, p2); } if (get_type (p2) == PATCH_BIRTH) { if (get_author (p2) == a1) return false; return swap_basic (p1, p2); } if (get_type (p1) == PATCH_MODIFICATION && get_type (p2) == PATCH_MODIFICATION) { modification m1= get_modification (p1); modification m2= get_modification (p2); modification i1= get_inverse (p1); modification i2= get_inverse (p2); bool r= swap (m1, m2); bool v= swap (i2, i1); p1= patch (m1, i1); p2= patch (m2, i2); return r && v && possible_inverse (m1, i1) && possible_inverse (m2, i2); } FAILED ("invalid situation"); return false; }
bool swap (modification& m1, modification& m2) { // Assuming that m1;m2 (the patch m1 followed by m2) is well-defined, // determine modifications m1* and m2* such that m2*;m1* is equivalent // to m1;m2. If such modifications exist, then set m1 := m2* and // m2 := m1* and return true. Otherwise, return false path rp1= root (m1); path rp2= root (m2); if (is_nil (rp1)) switch (m1->k) { case MOD_ASSIGN: { if (m1 == m2) return true; if (!is_nil (rp2) || m2->k != MOD_INSERT_NODE) return false; modification aux= m2; m2= modification (m1->k, path (m2->p->item, m1->p), m1->t); m1= aux; return true; } case MOD_INSERT: { if (is_nil (m2->p)) return false; int b= m1->p->item; int e= b + insert_length (m1->t); if (m2->p->item >= b && m2->p->item < e) if (!is_nil (root (m2)) || m2->p->item != b || m2->k != MOD_INSERT) if (!is_nil (root (m2)) || m2->k != MOD_INSERT_NODE) return false; return swap1 (m1, m2, b, e-b); } case MOD_REMOVE: { if (is_nil (m2->p)) return false; int i= m1->p->item; int d= m1->p->next->item; return swap1 (m1, m2, i, -d); } case MOD_SPLIT: { if (is_nil (m2->p)) return false; int i= m1->p->item; if (m2->p->item == i || m2->p->item == i+1) if (!is_nil (root (m2)) || m2->p->item != i || m2->k != MOD_INSERT) if (!is_nil (root (m2)) || m2->k != MOD_INSERT_NODE) return false; return swap1 (m1, m2, i, 1); } case MOD_JOIN: { if (is_nil (m2->p)) return false; int i= m1->p->item; if (m2->p->item == i) if (!is_nil (root (m2)) || m2->k != MOD_INSERT) return false; return swap1 (m1, m2, i, -1); } case MOD_ASSIGN_NODE: { if (!is_nil (root (m2))) return swap_basic (m1, m2); if (m1 == m2) return true; if (!is_nil (rp2) || m2->k != MOD_INSERT_NODE) return false; modification aux= m2; m2= modification (m1->k, path (m2->p->item, m1->p), m1->t); m1= aux; return true; } case MOD_INSERT_NODE: { if (is_nil (root (m2))) return false; if (m2->p->item != m1->p->item) return false; modification aux= m1; m1= modification (m2->k, m2->p->next, m2->t); if (m2->k != MOD_INSERT_NODE || !is_nil (root (m1))) m2= aux; else m2= modification (aux->k, path (m1->p->item, aux->p), aux->t); return true; } case MOD_REMOVE_NODE: { modification aux= m1; m1= modification (m2->k, path (m1->p->item, m2->p), m2->t); m2= aux; return true; } case MOD_SET_CURSOR: { if (!is_nil (rp2) || m2->k == MOD_JOIN || m2->k == MOD_SPLIT || m2->k == MOD_ASSIGN_NODE) return swap_basic (m1, m2); return false; } } else if (is_nil (rp2)) switch (m2->k) { case MOD_ASSIGN: return false; case MOD_INSERT: { int b= m2->p->item; int e= b + insert_length (m2->t); return swap2 (m1, m2, b, e-b); } case MOD_REMOVE: { int b= m2->p->item; int e= b + m2->p->next->item; if (m1->p->item >= b && m1->p->item < e) return false; return swap2 (m1, m2, b, b-e); } case MOD_SPLIT: { int i= m2->p->item; if (m1->p->item == i) return false; return swap2 (m1, m2, i, 1); } case MOD_JOIN: { int i= m2->p->item; if (m1->p->item == i || m1->p->item == i+1) return false; return swap2 (m1, m2, i, -1); } case MOD_ASSIGN_NODE: return swap_basic (m1, m2); case MOD_INSERT_NODE: { modification aux= m2; m2= modification (m1->k, path (m2->p->item, m1->p), m1->t); m1= aux; return true; } case MOD_REMOVE_NODE: { if (m1->p->item != m2->p->item) return false; modification aux= m2; m2= modification (m1->k, m1->p->next, m1->t); m1= aux; return true; } case MOD_SET_CURSOR: { if (!is_nil (rp1) || m1->k == MOD_JOIN || m1->k == MOD_SPLIT || m1->k == MOD_ASSIGN_NODE) return swap_basic (m1, m2); return false; } } else if (rp1->item == rp2->item) { path h (rp1->item); modification s1= m1 / h; modification s2= m2 / h; bool r= swap (s1, s2); m1= h * s1; m2= h * s2; return r; } else return swap_basic (m1, m2); FAILED ("unexpected situation"); }