diff --git a/lib/modules/Array.pmod b/lib/modules/Array.pmod index c5c405614e8d239bfb74030d8bd85533fa92aa8a..3e95e25aae625e8d7e8558d12e351f9d016c55ed 100644 --- a/lib/modules/Array.pmod +++ b/lib/modules/Array.pmod @@ -233,9 +233,91 @@ array transpose_old(array x) return ret; } +// diff3, complement to diff + +array(array(array)) diff3 (array a, array b, array c) +{ + // This does not necessarily produce the optimal sequence between + // all three arrays. A diff_longest_sequence() that takes any number + // of arrays would be nice. + array(int) seq_ab = diff_longest_sequence (a, b); + array(int) seq_bc = diff_longest_sequence (b, c); + array(int) seq_ca = diff_longest_sequence (c, a); + + // A number bigger than any valid index servers as end of array marker. + int eoa = max (sizeof (a), sizeof (b), sizeof (c)); + + array(int) ab = allocate (sizeof (a) + 1, -1); + array(int) ac = allocate (sizeof (a) + 1, -1); + ab[sizeof (a)] = ac[sizeof (a)] = eoa; + array(int) bc = allocate (sizeof (b) + 1, -1); + array(int) ba = allocate (sizeof (b) + 1, -1); + bc[sizeof (b)] = ba[sizeof (b)] = eoa; + array(int) ca = allocate (sizeof (c) + 1, -1); + array(int) cb = allocate (sizeof (c) + 1, -1); + ca[sizeof (c)] = cb[sizeof (c)] = eoa; + + for (int i = 0, j = 0; j < sizeof (seq_ab); i++) + if (a[i] == b[seq_ab[j]]) ab[i] = seq_ab[j], ba[seq_ab[j]] = i, j++; + for (int i = 0, j = 0; j < sizeof (seq_bc); i++) + if (b[i] == c[seq_bc[j]]) bc[i] = seq_bc[j], cb[seq_bc[j]] = i, j++; + for (int i = 0, j = 0; j < sizeof (seq_ca); i++) + if (c[i] == a[seq_ca[j]]) ca[i] = seq_ca[j], ac[seq_ca[j]] = i, j++; + + array(array) ares = ({}), bres = ({}), cres = ({}); + int ai = 0, bi = 0, ci = 0; + int part = 8; // Chunk partition bitfield. + + while (min (ac[ai], ab[ai], ba[bi], bc[bi], cb[ci], ca[ci]) != eoa) { + int apart = (ac[ai] == -1 && 1) | (ab[ai] == -1 && 2); + int bpart = (ba[bi] == -1 && 2) | (bc[bi] == -1 && 4); + int cpart = (cb[ci] == -1 && 4) | (ca[ci] == -1 && 1); + int newpart = apart | bpart | cpart; + + if ((apart ^ bpart ^ cpart) == 7 && !(apart & bpart & cpart) && + apart && bpart && cpart) { + // Solve cyclically interlocking equivalences by arbitrary + // breaking one of them. + if (ac[ai] != -1) ca[ac[ai]] = -1, ac[ai] = -1; + if (ab[ai] != -1) ba[ab[ai]] = -1, ab[ai] = -1; + apart = 3; + } + + if ((part & newpart) == newpart) { + // If the previous block had the same equivalence partition or + // was a three-part conflict, we should tack any singleton + // equivalences we have onto it and mark them so they aren't + // used again below. + if (apart == 3) ares[-1] += ({a[ai++]}), apart = 8; + if (bpart == 6) bres[-1] += ({b[bi++]}), bpart = 8; + if (cpart == 5) cres[-1] += ({c[ci++]}), cpart = 8; + } + + if (newpart == part) { + // The previous block had exactly the same equivalence + // partition, so tack anything else onto it too, but mask + // singleton equivalences this time. + if ((part & 3) == apart && apart != 3) ares[-1] += ({a[ai++]}); + if ((part & 6) == bpart && bpart != 6) bres[-1] += ({b[bi++]}); + if ((part & 5) == cpart && cpart != 5) cres[-1] += ({c[ci++]}); + } + else { + // Start a new block. Wait with singleton equivalences (this may + // cause an extra iteration, but the necessary conditions to + // prevent that are tricky). + part = newpart; + ares += ({(part & 3) == apart && apart != 3 ? ({a[ai++]}) : ({})}); + bres += ({(part & 6) == bpart && bpart != 6 ? ({b[bi++]}) : ({})}); + cres += ({(part & 5) == cpart && cpart != 5 ? ({c[ci++]}) : ({})}); + } + } + + return ({ares, bres, cres}); +} + // diff3, complement to diff (alpha stage) -array(array(array(mixed))) diff3(array mid,array left,array right) +array(array(array(mixed))) diff3_old(array mid,array left,array right) { array lmid,ldst; array rmid,rdst; @@ -243,9 +325,9 @@ array(array(array(mixed))) diff3(array mid,array left,array right) [lmid,ldst]=diff(mid,left); [rmid,rdst]=diff(mid,right); + int l=0,r=0,n; array res=({}); int lpos=0,rpos=0; - int l=0,r=0,n; array eq=({}); int x;