xref: /src/contrib/libdiff/lib/diff_patience.c (revision 59c8e88e72633afbc47a4ace0d2170d00d51f7dc)
19eb461aaSDag-Erling Smørgrav /* Implementation of the Patience Diff algorithm invented by Bram Cohen:
29eb461aaSDag-Erling Smørgrav  * Divide a diff problem into smaller chunks by an LCS (Longest Common Sequence)
39eb461aaSDag-Erling Smørgrav  * of common-unique lines. */
49eb461aaSDag-Erling Smørgrav /*
59eb461aaSDag-Erling Smørgrav  * Copyright (c) 2020 Neels Hofmeyr <neels@hofmeyr.de>
69eb461aaSDag-Erling Smørgrav  *
79eb461aaSDag-Erling Smørgrav  * Permission to use, copy, modify, and distribute this software for any
89eb461aaSDag-Erling Smørgrav  * purpose with or without fee is hereby granted, provided that the above
99eb461aaSDag-Erling Smørgrav  * copyright notice and this permission notice appear in all copies.
109eb461aaSDag-Erling Smørgrav  *
119eb461aaSDag-Erling Smørgrav  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
129eb461aaSDag-Erling Smørgrav  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
139eb461aaSDag-Erling Smørgrav  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
149eb461aaSDag-Erling Smørgrav  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
159eb461aaSDag-Erling Smørgrav  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
169eb461aaSDag-Erling Smørgrav  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
179eb461aaSDag-Erling Smørgrav  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
189eb461aaSDag-Erling Smørgrav  */
199eb461aaSDag-Erling Smørgrav 
209eb461aaSDag-Erling Smørgrav #include <assert.h>
219eb461aaSDag-Erling Smørgrav #include <errno.h>
229eb461aaSDag-Erling Smørgrav #include <stdbool.h>
239eb461aaSDag-Erling Smørgrav #include <stdint.h>
249eb461aaSDag-Erling Smørgrav #include <stdio.h>
259eb461aaSDag-Erling Smørgrav #include <stdlib.h>
269eb461aaSDag-Erling Smørgrav 
279eb461aaSDag-Erling Smørgrav #include <arraylist.h>
289eb461aaSDag-Erling Smørgrav #include <diff_main.h>
299eb461aaSDag-Erling Smørgrav 
309eb461aaSDag-Erling Smørgrav #include "diff_internal.h"
319eb461aaSDag-Erling Smørgrav #include "diff_debug.h"
329eb461aaSDag-Erling Smørgrav 
339eb461aaSDag-Erling Smørgrav /* Algorithm to find unique lines:
349eb461aaSDag-Erling Smørgrav  * 0: stupidly iterate atoms
359eb461aaSDag-Erling Smørgrav  * 1: qsort
369eb461aaSDag-Erling Smørgrav  * 2: mergesort
379eb461aaSDag-Erling Smørgrav  */
389eb461aaSDag-Erling Smørgrav #define UNIQUE_STRATEGY 1
399eb461aaSDag-Erling Smørgrav 
409eb461aaSDag-Erling Smørgrav /* Per-atom state for the Patience Diff algorithm */
419eb461aaSDag-Erling Smørgrav struct atom_patience {
429eb461aaSDag-Erling Smørgrav #if UNIQUE_STRATEGY == 0
439eb461aaSDag-Erling Smørgrav 	bool unique_here;
449eb461aaSDag-Erling Smørgrav #endif
459eb461aaSDag-Erling Smørgrav 	bool unique_in_both;
469eb461aaSDag-Erling Smørgrav 	struct diff_atom *pos_in_other;
479eb461aaSDag-Erling Smørgrav 	struct diff_atom *prev_stack;
489eb461aaSDag-Erling Smørgrav 	struct diff_range identical_lines;
499eb461aaSDag-Erling Smørgrav };
509eb461aaSDag-Erling Smørgrav 
519eb461aaSDag-Erling Smørgrav /* A diff_atom has a backpointer to the root diff_data. That points to the
529eb461aaSDag-Erling Smørgrav  * current diff_data, a possibly smaller section of the root. That current
539eb461aaSDag-Erling Smørgrav  * diff_data->algo_data is a pointer to an array of struct atom_patience. The
549eb461aaSDag-Erling Smørgrav  * atom's index in current diff_data gives the index in the atom_patience array.
559eb461aaSDag-Erling Smørgrav  */
569eb461aaSDag-Erling Smørgrav #define PATIENCE(ATOM) \
579eb461aaSDag-Erling Smørgrav 	(((struct atom_patience*)((ATOM)->root->current->algo_data))\
589eb461aaSDag-Erling Smørgrav 	 [diff_atom_idx((ATOM)->root->current, ATOM)])
599eb461aaSDag-Erling Smørgrav 
609eb461aaSDag-Erling Smørgrav #if UNIQUE_STRATEGY == 0
619eb461aaSDag-Erling Smørgrav 
629eb461aaSDag-Erling Smørgrav /* Stupid iteration and comparison of all atoms */
639eb461aaSDag-Erling Smørgrav static int
diff_atoms_mark_unique(struct diff_data * d,unsigned int * unique_count)649eb461aaSDag-Erling Smørgrav diff_atoms_mark_unique(struct diff_data *d, unsigned int *unique_count)
659eb461aaSDag-Erling Smørgrav {
669eb461aaSDag-Erling Smørgrav 	struct diff_atom *i;
679eb461aaSDag-Erling Smørgrav 	unsigned int count = 0;
689eb461aaSDag-Erling Smørgrav 	diff_data_foreach_atom(i, d) {
699eb461aaSDag-Erling Smørgrav 		PATIENCE(i).unique_here = true;
709eb461aaSDag-Erling Smørgrav 		PATIENCE(i).unique_in_both = true;
719eb461aaSDag-Erling Smørgrav 		count++;
729eb461aaSDag-Erling Smørgrav 	}
739eb461aaSDag-Erling Smørgrav 	diff_data_foreach_atom(i, d) {
749eb461aaSDag-Erling Smørgrav 		struct diff_atom *j;
759eb461aaSDag-Erling Smørgrav 
769eb461aaSDag-Erling Smørgrav 		if (!PATIENCE(i).unique_here)
779eb461aaSDag-Erling Smørgrav 			continue;
789eb461aaSDag-Erling Smørgrav 
799eb461aaSDag-Erling Smørgrav 		diff_data_foreach_atom_from(i + 1, j, d) {
809eb461aaSDag-Erling Smørgrav 			bool same;
819eb461aaSDag-Erling Smørgrav 			int r = diff_atom_same(&same, i, j);
829eb461aaSDag-Erling Smørgrav 			if (r)
839eb461aaSDag-Erling Smørgrav 				return r;
849eb461aaSDag-Erling Smørgrav 			if (!same)
859eb461aaSDag-Erling Smørgrav 				continue;
869eb461aaSDag-Erling Smørgrav 			if (PATIENCE(i).unique_here) {
879eb461aaSDag-Erling Smørgrav 				PATIENCE(i).unique_here = false;
889eb461aaSDag-Erling Smørgrav 				PATIENCE(i).unique_in_both = false;
899eb461aaSDag-Erling Smørgrav 				count--;
909eb461aaSDag-Erling Smørgrav 			}
919eb461aaSDag-Erling Smørgrav 			PATIENCE(j).unique_here = false;
929eb461aaSDag-Erling Smørgrav 			PATIENCE(j).unique_in_both = false;
939eb461aaSDag-Erling Smørgrav 			count--;
949eb461aaSDag-Erling Smørgrav 		}
959eb461aaSDag-Erling Smørgrav 	}
969eb461aaSDag-Erling Smørgrav 	if (unique_count)
979eb461aaSDag-Erling Smørgrav 		*unique_count = count;
989eb461aaSDag-Erling Smørgrav 	return 0;
999eb461aaSDag-Erling Smørgrav }
1009eb461aaSDag-Erling Smørgrav 
1019eb461aaSDag-Erling Smørgrav /* Mark those lines as PATIENCE(atom).unique_in_both = true that appear exactly
1029eb461aaSDag-Erling Smørgrav  * once in each side. */
1039eb461aaSDag-Erling Smørgrav static int
diff_atoms_mark_unique_in_both(struct diff_data * left,struct diff_data * right,unsigned int * unique_in_both_count)1049eb461aaSDag-Erling Smørgrav diff_atoms_mark_unique_in_both(struct diff_data *left, struct diff_data *right,
1059eb461aaSDag-Erling Smørgrav 			       unsigned int *unique_in_both_count)
1069eb461aaSDag-Erling Smørgrav {
1079eb461aaSDag-Erling Smørgrav 	/* Derive the final unique_in_both count without needing an explicit
1089eb461aaSDag-Erling Smørgrav 	 * iteration. So this is just some optimiziation to save one iteration
1099eb461aaSDag-Erling Smørgrav 	 * in the end. */
1109eb461aaSDag-Erling Smørgrav 	unsigned int unique_in_both;
1119eb461aaSDag-Erling Smørgrav 	int r;
1129eb461aaSDag-Erling Smørgrav 
1139eb461aaSDag-Erling Smørgrav 	r = diff_atoms_mark_unique(left, &unique_in_both);
1149eb461aaSDag-Erling Smørgrav 	if (r)
1159eb461aaSDag-Erling Smørgrav 		return r;
1169eb461aaSDag-Erling Smørgrav 	r = diff_atoms_mark_unique(right, NULL);
1179eb461aaSDag-Erling Smørgrav 	if (r)
1189eb461aaSDag-Erling Smørgrav 		return r;
1199eb461aaSDag-Erling Smørgrav 
1209eb461aaSDag-Erling Smørgrav 	debug("unique_in_both %u\n", unique_in_both);
1219eb461aaSDag-Erling Smørgrav 
1229eb461aaSDag-Erling Smørgrav 	struct diff_atom *i;
1239eb461aaSDag-Erling Smørgrav 	diff_data_foreach_atom(i, left) {
1249eb461aaSDag-Erling Smørgrav 		if (!PATIENCE(i).unique_here)
1259eb461aaSDag-Erling Smørgrav 			continue;
1269eb461aaSDag-Erling Smørgrav 		struct diff_atom *j;
1279eb461aaSDag-Erling Smørgrav 		int found_in_b = 0;
1289eb461aaSDag-Erling Smørgrav 		diff_data_foreach_atom(j, right) {
1299eb461aaSDag-Erling Smørgrav 			bool same;
1309eb461aaSDag-Erling Smørgrav 			int r = diff_atom_same(&same, i, j);
1319eb461aaSDag-Erling Smørgrav 			if (r)
1329eb461aaSDag-Erling Smørgrav 				return r;
1339eb461aaSDag-Erling Smørgrav 			if (!same)
1349eb461aaSDag-Erling Smørgrav 				continue;
1359eb461aaSDag-Erling Smørgrav 			if (!PATIENCE(j).unique_here) {
1369eb461aaSDag-Erling Smørgrav 				found_in_b = 2; /* or more */
1379eb461aaSDag-Erling Smørgrav 				break;
1389eb461aaSDag-Erling Smørgrav 			} else {
1399eb461aaSDag-Erling Smørgrav 				found_in_b = 1;
1409eb461aaSDag-Erling Smørgrav 				PATIENCE(j).pos_in_other = i;
1419eb461aaSDag-Erling Smørgrav 				PATIENCE(i).pos_in_other = j;
1429eb461aaSDag-Erling Smørgrav 			}
1439eb461aaSDag-Erling Smørgrav 		}
1449eb461aaSDag-Erling Smørgrav 
1459eb461aaSDag-Erling Smørgrav 		if (found_in_b == 0 || found_in_b > 1) {
1469eb461aaSDag-Erling Smørgrav 			PATIENCE(i).unique_in_both = false;
1479eb461aaSDag-Erling Smørgrav 			unique_in_both--;
1489eb461aaSDag-Erling Smørgrav 			debug("unique_in_both %u  (%d) ", unique_in_both,
1499eb461aaSDag-Erling Smørgrav 			      found_in_b);
1509eb461aaSDag-Erling Smørgrav 			debug_dump_atom(left, NULL, i);
1519eb461aaSDag-Erling Smørgrav 		}
1529eb461aaSDag-Erling Smørgrav 	}
1539eb461aaSDag-Erling Smørgrav 
1549eb461aaSDag-Erling Smørgrav 	/* Still need to unmark right[*]->patience.unique_in_both for atoms that
1559eb461aaSDag-Erling Smørgrav 	 * don't exist in left */
1569eb461aaSDag-Erling Smørgrav 	diff_data_foreach_atom(i, right) {
1579eb461aaSDag-Erling Smørgrav 		if (!PATIENCE(i).unique_here
1589eb461aaSDag-Erling Smørgrav 		    || !PATIENCE(i).unique_in_both)
1599eb461aaSDag-Erling Smørgrav 			continue;
1609eb461aaSDag-Erling Smørgrav 		struct diff_atom *j;
1619eb461aaSDag-Erling Smørgrav 		bool found_in_a = false;
1629eb461aaSDag-Erling Smørgrav 		diff_data_foreach_atom(j, left) {
1639eb461aaSDag-Erling Smørgrav 			bool same;
1649eb461aaSDag-Erling Smørgrav 			int r;
1659eb461aaSDag-Erling Smørgrav 			if (!PATIENCE(j).unique_in_both)
1669eb461aaSDag-Erling Smørgrav 				continue;
1679eb461aaSDag-Erling Smørgrav 			r = diff_atom_same(&same, i, j);
1689eb461aaSDag-Erling Smørgrav 			if (r)
1699eb461aaSDag-Erling Smørgrav 				return r;
1709eb461aaSDag-Erling Smørgrav 			if (!same)
1719eb461aaSDag-Erling Smørgrav 				continue;
1729eb461aaSDag-Erling Smørgrav 			found_in_a = true;
1739eb461aaSDag-Erling Smørgrav 			break;
1749eb461aaSDag-Erling Smørgrav 		}
1759eb461aaSDag-Erling Smørgrav 
1769eb461aaSDag-Erling Smørgrav 		if (!found_in_a)
1779eb461aaSDag-Erling Smørgrav 			PATIENCE(i).unique_in_both = false;
1789eb461aaSDag-Erling Smørgrav 	}
1799eb461aaSDag-Erling Smørgrav 
1809eb461aaSDag-Erling Smørgrav 	if (unique_in_both_count)
1819eb461aaSDag-Erling Smørgrav 		*unique_in_both_count = unique_in_both;
1829eb461aaSDag-Erling Smørgrav 	return 0;
1839eb461aaSDag-Erling Smørgrav }
1849eb461aaSDag-Erling Smørgrav 
1859eb461aaSDag-Erling Smørgrav #else /* UNIQUE_STRATEGY != 0 */
1869eb461aaSDag-Erling Smørgrav 
1879eb461aaSDag-Erling Smørgrav /* Use an optimized sorting algorithm (qsort, mergesort) to find unique lines */
1889eb461aaSDag-Erling Smørgrav 
diff_atoms_compar(const void * _a,const void * _b)1899eb461aaSDag-Erling Smørgrav static int diff_atoms_compar(const void *_a, const void *_b)
1909eb461aaSDag-Erling Smørgrav {
1919eb461aaSDag-Erling Smørgrav 	const struct diff_atom *a = *(struct diff_atom**)_a;
1929eb461aaSDag-Erling Smørgrav 	const struct diff_atom *b = *(struct diff_atom**)_b;
1939eb461aaSDag-Erling Smørgrav 	int cmp;
1949eb461aaSDag-Erling Smørgrav 	int rc = 0;
1959eb461aaSDag-Erling Smørgrav 
1969eb461aaSDag-Erling Smørgrav 	/* If there's been an error (e.g. I/O error) in a previous compar, we
1979eb461aaSDag-Erling Smørgrav 	 * have no way to abort the sort but just report the rc and stop
1989eb461aaSDag-Erling Smørgrav 	 * comparing. Make sure to catch errors on either side. If atoms are
1999eb461aaSDag-Erling Smørgrav 	 * from more than one diff_data, make sure the error, if any, spreads
2009eb461aaSDag-Erling Smørgrav 	 * to all of them, so we can cut short all future comparisons. */
2019eb461aaSDag-Erling Smørgrav 	if (a->root->err)
2029eb461aaSDag-Erling Smørgrav 		rc = a->root->err;
2039eb461aaSDag-Erling Smørgrav 	if (b->root->err)
2049eb461aaSDag-Erling Smørgrav 		rc = b->root->err;
2059eb461aaSDag-Erling Smørgrav 	if (rc) {
2069eb461aaSDag-Erling Smørgrav 		a->root->err = rc;
2079eb461aaSDag-Erling Smørgrav 		b->root->err = rc;
2089eb461aaSDag-Erling Smørgrav 		/* just return 'equal' to not swap more positions */
2099eb461aaSDag-Erling Smørgrav 		return 0;
2109eb461aaSDag-Erling Smørgrav 	}
2119eb461aaSDag-Erling Smørgrav 
2129eb461aaSDag-Erling Smørgrav 	/* Sort by the simplistic hash */
2139eb461aaSDag-Erling Smørgrav 	if (a->hash < b->hash)
2149eb461aaSDag-Erling Smørgrav 		return -1;
2159eb461aaSDag-Erling Smørgrav 	if (a->hash > b->hash)
2169eb461aaSDag-Erling Smørgrav 		return 1;
2179eb461aaSDag-Erling Smørgrav 
2189eb461aaSDag-Erling Smørgrav 	/* If hashes are the same, the lines may still differ. Do a full cmp. */
2199eb461aaSDag-Erling Smørgrav 	rc = diff_atom_cmp(&cmp, a, b);
2209eb461aaSDag-Erling Smørgrav 
2219eb461aaSDag-Erling Smørgrav 	if (rc) {
2229eb461aaSDag-Erling Smørgrav 		/* Mark the I/O error so that the caller can find out about it.
2239eb461aaSDag-Erling Smørgrav 		 * For the case atoms are from more than one diff_data, mark in
2249eb461aaSDag-Erling Smørgrav 		 * both. */
2259eb461aaSDag-Erling Smørgrav 		a->root->err = rc;
2269eb461aaSDag-Erling Smørgrav 		if (a->root != b->root)
2279eb461aaSDag-Erling Smørgrav 			b->root->err = rc;
2289eb461aaSDag-Erling Smørgrav 		return 0;
2299eb461aaSDag-Erling Smørgrav 	}
2309eb461aaSDag-Erling Smørgrav 
2319eb461aaSDag-Erling Smørgrav 	return cmp;
2329eb461aaSDag-Erling Smørgrav }
2339eb461aaSDag-Erling Smørgrav 
2349eb461aaSDag-Erling Smørgrav /* Sort an array of struct diff_atom* in-place. */
diff_atoms_sort(struct diff_atom * atoms[],size_t atoms_count)2359eb461aaSDag-Erling Smørgrav static int diff_atoms_sort(struct diff_atom *atoms[],
2369eb461aaSDag-Erling Smørgrav 			   size_t atoms_count)
2379eb461aaSDag-Erling Smørgrav {
2389eb461aaSDag-Erling Smørgrav #if UNIQUE_STRATEGY == 1
2399eb461aaSDag-Erling Smørgrav 	qsort(atoms, atoms_count, sizeof(struct diff_atom*), diff_atoms_compar);
2409eb461aaSDag-Erling Smørgrav #else
2419eb461aaSDag-Erling Smørgrav 	mergesort(atoms, atoms_count, sizeof(struct diff_atom*),
2429eb461aaSDag-Erling Smørgrav 		  diff_atoms_compar);
2439eb461aaSDag-Erling Smørgrav #endif
2449eb461aaSDag-Erling Smørgrav 	return atoms[0]->root->err;
2459eb461aaSDag-Erling Smørgrav }
2469eb461aaSDag-Erling Smørgrav 
2479eb461aaSDag-Erling Smørgrav static int
diff_atoms_mark_unique_in_both(struct diff_data * left,struct diff_data * right,unsigned int * unique_in_both_count_p)2489eb461aaSDag-Erling Smørgrav diff_atoms_mark_unique_in_both(struct diff_data *left, struct diff_data *right,
2499eb461aaSDag-Erling Smørgrav 			       unsigned int *unique_in_both_count_p)
2509eb461aaSDag-Erling Smørgrav {
2519eb461aaSDag-Erling Smørgrav 	struct diff_atom *a;
2529eb461aaSDag-Erling Smørgrav 	struct diff_atom *b;
2539eb461aaSDag-Erling Smørgrav 	struct diff_atom **all_atoms;
2549eb461aaSDag-Erling Smørgrav 	unsigned int len = 0;
2559eb461aaSDag-Erling Smørgrav 	unsigned int i;
2569eb461aaSDag-Erling Smørgrav 	unsigned int unique_in_both_count = 0;
2579eb461aaSDag-Erling Smørgrav 	int rc;
2589eb461aaSDag-Erling Smørgrav 
2599eb461aaSDag-Erling Smørgrav 	all_atoms = calloc(left->atoms.len + right->atoms.len,
2609eb461aaSDag-Erling Smørgrav 	    sizeof(struct diff_atom *));
2619eb461aaSDag-Erling Smørgrav 	if (all_atoms == NULL)
2629eb461aaSDag-Erling Smørgrav 		return ENOMEM;
2639eb461aaSDag-Erling Smørgrav 
2649eb461aaSDag-Erling Smørgrav 	left->err = 0;
2659eb461aaSDag-Erling Smørgrav 	right->err = 0;
2669eb461aaSDag-Erling Smørgrav 	left->root->err = 0;
2679eb461aaSDag-Erling Smørgrav 	right->root->err = 0;
2689eb461aaSDag-Erling Smørgrav 	diff_data_foreach_atom(a, left) {
2699eb461aaSDag-Erling Smørgrav 		all_atoms[len++] = a;
2709eb461aaSDag-Erling Smørgrav 	}
2719eb461aaSDag-Erling Smørgrav 	diff_data_foreach_atom(b, right) {
2729eb461aaSDag-Erling Smørgrav 		all_atoms[len++] = b;
2739eb461aaSDag-Erling Smørgrav 	}
2749eb461aaSDag-Erling Smørgrav 
2759eb461aaSDag-Erling Smørgrav 	rc = diff_atoms_sort(all_atoms, len);
2769eb461aaSDag-Erling Smørgrav 	if (rc)
2779eb461aaSDag-Erling Smørgrav 		goto free_and_exit;
2789eb461aaSDag-Erling Smørgrav 
2799eb461aaSDag-Erling Smørgrav 	/* Now we have a sorted array of atom pointers. All similar lines are
2809eb461aaSDag-Erling Smørgrav 	 * adjacent. Walk through the array and mark those that are unique on
2819eb461aaSDag-Erling Smørgrav 	 * each side, but exist once in both sources. */
2829eb461aaSDag-Erling Smørgrav 	for (i = 0; i < len; i++) {
2839eb461aaSDag-Erling Smørgrav 		bool same;
2849eb461aaSDag-Erling Smørgrav 		unsigned int next_differing_i;
2859eb461aaSDag-Erling Smørgrav 		unsigned int last_identical_i;
2869eb461aaSDag-Erling Smørgrav 		unsigned int j;
2879eb461aaSDag-Erling Smørgrav 		unsigned int count_first_side = 1;
2889eb461aaSDag-Erling Smørgrav 		unsigned int count_other_side = 0;
2899eb461aaSDag-Erling Smørgrav 		a = all_atoms[i];
2909eb461aaSDag-Erling Smørgrav 		debug("a: ");
2919eb461aaSDag-Erling Smørgrav 		debug_dump_atom(a->root, NULL, a);
2929eb461aaSDag-Erling Smørgrav 
2939eb461aaSDag-Erling Smørgrav 		/* Do as few diff_atom_cmp() as possible: first walk forward
2949eb461aaSDag-Erling Smørgrav 		 * only using the cheap hash as indicator for differing atoms;
2959eb461aaSDag-Erling Smørgrav 		 * then walk backwards until hitting an identical atom. */
2969eb461aaSDag-Erling Smørgrav 		for (next_differing_i = i + 1; next_differing_i < len;
2979eb461aaSDag-Erling Smørgrav 		     next_differing_i++) {
2989eb461aaSDag-Erling Smørgrav 			b = all_atoms[next_differing_i];
2999eb461aaSDag-Erling Smørgrav 			if (a->hash != b->hash)
3009eb461aaSDag-Erling Smørgrav 				break;
3019eb461aaSDag-Erling Smørgrav 		}
3029eb461aaSDag-Erling Smørgrav 		for (last_identical_i = next_differing_i - 1;
3039eb461aaSDag-Erling Smørgrav 		     last_identical_i > i;
3049eb461aaSDag-Erling Smørgrav 		     last_identical_i--) {
3059eb461aaSDag-Erling Smørgrav 			b = all_atoms[last_identical_i];
3069eb461aaSDag-Erling Smørgrav 			rc = diff_atom_same(&same, a, b);
3079eb461aaSDag-Erling Smørgrav 			if (rc)
3089eb461aaSDag-Erling Smørgrav 				goto free_and_exit;
3099eb461aaSDag-Erling Smørgrav 			if (same)
3109eb461aaSDag-Erling Smørgrav 				break;
3119eb461aaSDag-Erling Smørgrav 		}
3129eb461aaSDag-Erling Smørgrav 		next_differing_i = last_identical_i + 1;
3139eb461aaSDag-Erling Smørgrav 
3149eb461aaSDag-Erling Smørgrav 		for (j = i+1; j < next_differing_i; j++) {
3159eb461aaSDag-Erling Smørgrav 			b = all_atoms[j];
3169eb461aaSDag-Erling Smørgrav 			/* A following atom is the same. See on which side the
3179eb461aaSDag-Erling Smørgrav 			 * repetition counts. */
3189eb461aaSDag-Erling Smørgrav 			if (a->root == b->root)
3199eb461aaSDag-Erling Smørgrav 				count_first_side ++;
3209eb461aaSDag-Erling Smørgrav 			else
3219eb461aaSDag-Erling Smørgrav 				count_other_side ++;
3229eb461aaSDag-Erling Smørgrav 			debug("b: ");
3239eb461aaSDag-Erling Smørgrav 			debug_dump_atom(b->root, NULL, b);
3249eb461aaSDag-Erling Smørgrav 			debug("   count_first_side=%d count_other_side=%d\n",
3259eb461aaSDag-Erling Smørgrav 			      count_first_side, count_other_side);
3269eb461aaSDag-Erling Smørgrav 		}
3279eb461aaSDag-Erling Smørgrav 
3289eb461aaSDag-Erling Smørgrav 		/* Counted a section of similar atoms, put the results back to
3299eb461aaSDag-Erling Smørgrav 		 * the atoms. */
3309eb461aaSDag-Erling Smørgrav 		if ((count_first_side == 1)
3319eb461aaSDag-Erling Smørgrav 		    && (count_other_side == 1)) {
3329eb461aaSDag-Erling Smørgrav 			b = all_atoms[i+1];
3339eb461aaSDag-Erling Smørgrav 			PATIENCE(a).unique_in_both = true;
3349eb461aaSDag-Erling Smørgrav 			PATIENCE(a).pos_in_other = b;
3359eb461aaSDag-Erling Smørgrav 			PATIENCE(b).unique_in_both = true;
3369eb461aaSDag-Erling Smørgrav 			PATIENCE(b).pos_in_other = a;
3379eb461aaSDag-Erling Smørgrav 			unique_in_both_count++;
3389eb461aaSDag-Erling Smørgrav 		}
3399eb461aaSDag-Erling Smørgrav 
3409eb461aaSDag-Erling Smørgrav 		/* j now points at the first atom after 'a' that is not
3419eb461aaSDag-Erling Smørgrav 		 * identical to 'a'. j is always > i. */
3429eb461aaSDag-Erling Smørgrav 		i = j - 1;
3439eb461aaSDag-Erling Smørgrav 	}
3449eb461aaSDag-Erling Smørgrav 	*unique_in_both_count_p = unique_in_both_count;
3459eb461aaSDag-Erling Smørgrav 	rc = 0;
3469eb461aaSDag-Erling Smørgrav free_and_exit:
3479eb461aaSDag-Erling Smørgrav 	free(all_atoms);
3489eb461aaSDag-Erling Smørgrav 	return rc;
3499eb461aaSDag-Erling Smørgrav }
3509eb461aaSDag-Erling Smørgrav #endif /* UNIQUE_STRATEGY != 0 */
3519eb461aaSDag-Erling Smørgrav 
3529eb461aaSDag-Erling Smørgrav /* binary search to find the stack to put this atom "card" on. */
3539eb461aaSDag-Erling Smørgrav static int
find_target_stack(struct diff_atom * atom,struct diff_atom ** patience_stacks,unsigned int patience_stacks_count)3549eb461aaSDag-Erling Smørgrav find_target_stack(struct diff_atom *atom,
3559eb461aaSDag-Erling Smørgrav 		  struct diff_atom **patience_stacks,
3569eb461aaSDag-Erling Smørgrav 		  unsigned int patience_stacks_count)
3579eb461aaSDag-Erling Smørgrav {
3589eb461aaSDag-Erling Smørgrav 	unsigned int lo = 0;
3599eb461aaSDag-Erling Smørgrav 	unsigned int hi = patience_stacks_count;
3609eb461aaSDag-Erling Smørgrav 	while (lo < hi) {
3619eb461aaSDag-Erling Smørgrav 		unsigned int mid = (lo + hi) >> 1;
3629eb461aaSDag-Erling Smørgrav 
3639eb461aaSDag-Erling Smørgrav 		if (PATIENCE(patience_stacks[mid]).pos_in_other
3649eb461aaSDag-Erling Smørgrav 		    < PATIENCE(atom).pos_in_other)
3659eb461aaSDag-Erling Smørgrav 			lo = mid + 1;
3669eb461aaSDag-Erling Smørgrav 		else
3679eb461aaSDag-Erling Smørgrav 			hi = mid;
3689eb461aaSDag-Erling Smørgrav 	}
3699eb461aaSDag-Erling Smørgrav 	return lo;
3709eb461aaSDag-Erling Smørgrav }
3719eb461aaSDag-Erling Smørgrav 
3729eb461aaSDag-Erling Smørgrav /* Among the lines that appear exactly once in each side, find the longest
3739eb461aaSDag-Erling Smørgrav  * streak that appear in both files in the same order (with other stuff allowed
3749eb461aaSDag-Erling Smørgrav  * to interleave). Use patience sort for that, as in the Patience Diff
3759eb461aaSDag-Erling Smørgrav  * algorithm.
3769eb461aaSDag-Erling Smørgrav  * See https://bramcohen.livejournal.com/73318.html and, for a much more
3779eb461aaSDag-Erling Smørgrav  * detailed explanation,
3789eb461aaSDag-Erling Smørgrav  * https://blog.jcoglan.com/2017/09/19/the-patience-diff-algorithm/ */
3799eb461aaSDag-Erling Smørgrav int
diff_algo_patience(const struct diff_algo_config * algo_config,struct diff_state * state)3809eb461aaSDag-Erling Smørgrav diff_algo_patience(const struct diff_algo_config *algo_config,
3819eb461aaSDag-Erling Smørgrav 		   struct diff_state *state)
3829eb461aaSDag-Erling Smørgrav {
3839eb461aaSDag-Erling Smørgrav 	int rc;
3849eb461aaSDag-Erling Smørgrav 	struct diff_data *left = &state->left;
3859eb461aaSDag-Erling Smørgrav 	struct diff_data *right = &state->right;
3869eb461aaSDag-Erling Smørgrav 	struct atom_patience *atom_patience_left =
3879eb461aaSDag-Erling Smørgrav 		calloc(left->atoms.len, sizeof(struct atom_patience));
3889eb461aaSDag-Erling Smørgrav 	struct atom_patience *atom_patience_right =
3899eb461aaSDag-Erling Smørgrav 		calloc(right->atoms.len, sizeof(struct atom_patience));
3909eb461aaSDag-Erling Smørgrav 	unsigned int unique_in_both_count;
3919eb461aaSDag-Erling Smørgrav 	struct diff_atom **lcs = NULL;
3929eb461aaSDag-Erling Smørgrav 
3939eb461aaSDag-Erling Smørgrav 	debug("\n** %s\n", __func__);
3949eb461aaSDag-Erling Smørgrav 
3959eb461aaSDag-Erling Smørgrav 	left->root->current = left;
3969eb461aaSDag-Erling Smørgrav 	right->root->current = right;
3979eb461aaSDag-Erling Smørgrav 	left->algo_data = atom_patience_left;
3989eb461aaSDag-Erling Smørgrav 	right->algo_data = atom_patience_right;
3999eb461aaSDag-Erling Smørgrav 
4009eb461aaSDag-Erling Smørgrav 	/* Find those lines that appear exactly once in 'left' and exactly once
4019eb461aaSDag-Erling Smørgrav 	 * in 'right'. */
4029eb461aaSDag-Erling Smørgrav 	rc = diff_atoms_mark_unique_in_both(left, right, &unique_in_both_count);
4039eb461aaSDag-Erling Smørgrav 	if (rc)
4049eb461aaSDag-Erling Smørgrav 		goto free_and_exit;
4059eb461aaSDag-Erling Smørgrav 
4069eb461aaSDag-Erling Smørgrav 	debug("unique_in_both_count %u\n", unique_in_both_count);
4079eb461aaSDag-Erling Smørgrav 	debug("left:\n");
4089eb461aaSDag-Erling Smørgrav 	debug_dump(left);
4099eb461aaSDag-Erling Smørgrav 	debug("right:\n");
4109eb461aaSDag-Erling Smørgrav 	debug_dump(right);
4119eb461aaSDag-Erling Smørgrav 
4129eb461aaSDag-Erling Smørgrav 	if (!unique_in_both_count) {
4139eb461aaSDag-Erling Smørgrav 		/* Cannot apply Patience, tell the caller to use fallback_algo
4149eb461aaSDag-Erling Smørgrav 		 * instead. */
4159eb461aaSDag-Erling Smørgrav 		rc = DIFF_RC_USE_DIFF_ALGO_FALLBACK;
4169eb461aaSDag-Erling Smørgrav 		goto free_and_exit;
4179eb461aaSDag-Erling Smørgrav 	}
4189eb461aaSDag-Erling Smørgrav 
4199eb461aaSDag-Erling Smørgrav 	rc = ENOMEM;
4209eb461aaSDag-Erling Smørgrav 
4219eb461aaSDag-Erling Smørgrav 	/* An array of Longest Common Sequence is the result of the below
4229eb461aaSDag-Erling Smørgrav 	 * subscope: */
4239eb461aaSDag-Erling Smørgrav 	unsigned int lcs_count = 0;
4249eb461aaSDag-Erling Smørgrav 	struct diff_atom *lcs_tail = NULL;
4259eb461aaSDag-Erling Smørgrav 
4269eb461aaSDag-Erling Smørgrav 	{
4279eb461aaSDag-Erling Smørgrav 		/* This subscope marks the lifetime of the atom_pointers
4289eb461aaSDag-Erling Smørgrav 		 * allocation */
4299eb461aaSDag-Erling Smørgrav 
4309eb461aaSDag-Erling Smørgrav 		/* One chunk of storage for atom pointers */
4319eb461aaSDag-Erling Smørgrav 		struct diff_atom **atom_pointers;
4329eb461aaSDag-Erling Smørgrav 		atom_pointers = recallocarray(NULL, 0, unique_in_both_count * 2,
4339eb461aaSDag-Erling Smørgrav 					      sizeof(struct diff_atom*));
4349eb461aaSDag-Erling Smørgrav 		if (atom_pointers == NULL)
4359eb461aaSDag-Erling Smørgrav 			return ENOMEM;
4369eb461aaSDag-Erling Smørgrav 		/* Half for the list of atoms that still need to be put on
4379eb461aaSDag-Erling Smørgrav 		 * stacks */
4389eb461aaSDag-Erling Smørgrav 		struct diff_atom **uniques = atom_pointers;
4399eb461aaSDag-Erling Smørgrav 
4409eb461aaSDag-Erling Smørgrav 		/* Half for the patience sort state's "card stacks" -- we
4419eb461aaSDag-Erling Smørgrav 		 * remember only each stack's topmost "card" */
4429eb461aaSDag-Erling Smørgrav 		struct diff_atom **patience_stacks;
4439eb461aaSDag-Erling Smørgrav 		patience_stacks = atom_pointers + unique_in_both_count;
4449eb461aaSDag-Erling Smørgrav 		unsigned int patience_stacks_count = 0;
4459eb461aaSDag-Erling Smørgrav 
4469eb461aaSDag-Erling Smørgrav 		/* Take all common, unique items from 'left' ... */
4479eb461aaSDag-Erling Smørgrav 
4489eb461aaSDag-Erling Smørgrav 		struct diff_atom *atom;
4499eb461aaSDag-Erling Smørgrav 		struct diff_atom **uniques_end = uniques;
4509eb461aaSDag-Erling Smørgrav 		diff_data_foreach_atom(atom, left) {
4519eb461aaSDag-Erling Smørgrav 			if (!PATIENCE(atom).unique_in_both)
4529eb461aaSDag-Erling Smørgrav 				continue;
4539eb461aaSDag-Erling Smørgrav 			*uniques_end = atom;
4549eb461aaSDag-Erling Smørgrav 			uniques_end++;
4559eb461aaSDag-Erling Smørgrav 		}
4569eb461aaSDag-Erling Smørgrav 
4579eb461aaSDag-Erling Smørgrav 		/* ...and sort them to the order found in 'right'.
4589eb461aaSDag-Erling Smørgrav 		 * The idea is to find the leftmost stack that has a higher line
4599eb461aaSDag-Erling Smørgrav 		 * number and add it to the stack's top.
4609eb461aaSDag-Erling Smørgrav 		 * If there is no such stack, open a new one on the right. The
4619eb461aaSDag-Erling Smørgrav 		 * line number is derived from the atom*, which are array items
4629eb461aaSDag-Erling Smørgrav 		 * and hence reflect the relative position in the source file.
4639eb461aaSDag-Erling Smørgrav 		 * So we got the common-uniques from 'left' and sort them
4649eb461aaSDag-Erling Smørgrav 		 * according to PATIENCE(atom).pos_in_other. */
4659eb461aaSDag-Erling Smørgrav 		unsigned int i;
4669eb461aaSDag-Erling Smørgrav 		for (i = 0; i < unique_in_both_count; i++) {
4679eb461aaSDag-Erling Smørgrav 			atom = uniques[i];
4689eb461aaSDag-Erling Smørgrav 			unsigned int target_stack;
4699eb461aaSDag-Erling Smørgrav 			target_stack = find_target_stack(atom, patience_stacks,
4709eb461aaSDag-Erling Smørgrav 							 patience_stacks_count);
4719eb461aaSDag-Erling Smørgrav 			assert(target_stack <= patience_stacks_count);
4729eb461aaSDag-Erling Smørgrav 			patience_stacks[target_stack] = atom;
4739eb461aaSDag-Erling Smørgrav 			if (target_stack == patience_stacks_count)
4749eb461aaSDag-Erling Smørgrav 				patience_stacks_count++;
4759eb461aaSDag-Erling Smørgrav 
4769eb461aaSDag-Erling Smørgrav 			/* Record a back reference to the next stack on the
4779eb461aaSDag-Erling Smørgrav 			 * left, which will form the final longest sequence
4789eb461aaSDag-Erling Smørgrav 			 * later. */
4799eb461aaSDag-Erling Smørgrav 			PATIENCE(atom).prev_stack = target_stack ?
4809eb461aaSDag-Erling Smørgrav 				patience_stacks[target_stack - 1] : NULL;
4819eb461aaSDag-Erling Smørgrav 
4829eb461aaSDag-Erling Smørgrav 			{
4839eb461aaSDag-Erling Smørgrav 				int xx;
4849eb461aaSDag-Erling Smørgrav 				for (xx = 0; xx < patience_stacks_count; xx++) {
4859eb461aaSDag-Erling Smørgrav 					debug(" %s%d",
4869eb461aaSDag-Erling Smørgrav 					      (xx == target_stack) ? ">" : "",
4879eb461aaSDag-Erling Smørgrav 					      diff_atom_idx(right,
4889eb461aaSDag-Erling Smørgrav 							    PATIENCE(patience_stacks[xx]).pos_in_other));
4899eb461aaSDag-Erling Smørgrav 				}
4909eb461aaSDag-Erling Smørgrav 				debug("\n");
4919eb461aaSDag-Erling Smørgrav 			}
4929eb461aaSDag-Erling Smørgrav 		}
4939eb461aaSDag-Erling Smørgrav 
4949eb461aaSDag-Erling Smørgrav 		/* backtrace through prev_stack references to form the final
4959eb461aaSDag-Erling Smørgrav 		 * longest common sequence */
4969eb461aaSDag-Erling Smørgrav 		lcs_tail = patience_stacks[patience_stacks_count - 1];
4979eb461aaSDag-Erling Smørgrav 		lcs_count = patience_stacks_count;
4989eb461aaSDag-Erling Smørgrav 
4999eb461aaSDag-Erling Smørgrav 		/* uniques and patience_stacks are no longer needed.
5009eb461aaSDag-Erling Smørgrav 		 * Backpointers are in PATIENCE(atom).prev_stack */
5019eb461aaSDag-Erling Smørgrav 		free(atom_pointers);
5029eb461aaSDag-Erling Smørgrav 	}
5039eb461aaSDag-Erling Smørgrav 
5049eb461aaSDag-Erling Smørgrav 	lcs = recallocarray(NULL, 0, lcs_count, sizeof(struct diff_atom*));
5059eb461aaSDag-Erling Smørgrav 	struct diff_atom **lcs_backtrace_pos = &lcs[lcs_count - 1];
5069eb461aaSDag-Erling Smørgrav 	struct diff_atom *atom;
5079eb461aaSDag-Erling Smørgrav 	for (atom = lcs_tail; atom; atom = PATIENCE(atom).prev_stack, lcs_backtrace_pos--) {
5089eb461aaSDag-Erling Smørgrav 		assert(lcs_backtrace_pos >= lcs);
5099eb461aaSDag-Erling Smørgrav 		*lcs_backtrace_pos = atom;
5109eb461aaSDag-Erling Smørgrav 	}
5119eb461aaSDag-Erling Smørgrav 
5129eb461aaSDag-Erling Smørgrav 	unsigned int i;
5139eb461aaSDag-Erling Smørgrav 	if (DEBUG) {
5149eb461aaSDag-Erling Smørgrav 		debug("\npatience LCS:\n");
5159eb461aaSDag-Erling Smørgrav 		for (i = 0; i < lcs_count; i++) {
5169eb461aaSDag-Erling Smørgrav 			debug("\n L "); debug_dump_atom(left, right, lcs[i]);
5179eb461aaSDag-Erling Smørgrav 			debug(" R "); debug_dump_atom(right, left,
5189eb461aaSDag-Erling Smørgrav 						      PATIENCE(lcs[i]).pos_in_other);
5199eb461aaSDag-Erling Smørgrav 		}
5209eb461aaSDag-Erling Smørgrav 	}
5219eb461aaSDag-Erling Smørgrav 
5229eb461aaSDag-Erling Smørgrav 
5239eb461aaSDag-Erling Smørgrav 	/* TODO: For each common-unique line found (now listed in lcs), swallow
5249eb461aaSDag-Erling Smørgrav 	 * lines upwards and downwards that are identical on each side. Requires
5259eb461aaSDag-Erling Smørgrav 	 * a way to represent atoms being glued to adjacent atoms. */
5269eb461aaSDag-Erling Smørgrav 
5279eb461aaSDag-Erling Smørgrav 	debug("\ntraverse LCS, possibly recursing:\n");
5289eb461aaSDag-Erling Smørgrav 
5299eb461aaSDag-Erling Smørgrav 	/* Now we have pinned positions in both files at which it makes sense to
5309eb461aaSDag-Erling Smørgrav 	 * divide the diff problem into smaller chunks. Go into the next round:
5319eb461aaSDag-Erling Smørgrav 	 * look at each section in turn, trying to again find common-unique
5329eb461aaSDag-Erling Smørgrav 	 * lines in those smaller sections. As soon as no more are found, the
5339eb461aaSDag-Erling Smørgrav 	 * remaining smaller sections are solved by Myers. */
5349eb461aaSDag-Erling Smørgrav 	/* left_pos and right_pos are indexes in left/right->atoms.head until
5359eb461aaSDag-Erling Smørgrav 	 * which the atoms are already handled (added to result chunks). */
5369eb461aaSDag-Erling Smørgrav 	unsigned int left_pos = 0;
5379eb461aaSDag-Erling Smørgrav 	unsigned int right_pos = 0;
5389eb461aaSDag-Erling Smørgrav 	for (i = 0; i <= lcs_count; i++) {
5399eb461aaSDag-Erling Smørgrav 		struct diff_atom *atom;
5409eb461aaSDag-Erling Smørgrav 		struct diff_atom *atom_r;
5419eb461aaSDag-Erling Smørgrav 		/* left_idx and right_idx are indexes of the start of this
5429eb461aaSDag-Erling Smørgrav 		 * section of identical lines on both sides.
5439eb461aaSDag-Erling Smørgrav 		 * left_pos marks the index of the first still unhandled line,
5449eb461aaSDag-Erling Smørgrav 		 * left_idx is the start of an identical section some way
5459eb461aaSDag-Erling Smørgrav 		 * further down, and this loop adds an unsolved chunk of
5469eb461aaSDag-Erling Smørgrav 		 * [left_pos..left_idx[ and a solved chunk of
5479eb461aaSDag-Erling Smørgrav 		 * [left_idx..identical_lines.end[. */
5489eb461aaSDag-Erling Smørgrav 		unsigned int left_idx;
5499eb461aaSDag-Erling Smørgrav 		unsigned int right_idx;
5509eb461aaSDag-Erling Smørgrav 
5519eb461aaSDag-Erling Smørgrav 		debug("iteration %u of %u  left_pos %u  right_pos %u\n",
5529eb461aaSDag-Erling Smørgrav 		      i, lcs_count, left_pos, right_pos);
5539eb461aaSDag-Erling Smørgrav 
5549eb461aaSDag-Erling Smørgrav 		if (i < lcs_count) {
5559eb461aaSDag-Erling Smørgrav 			atom = lcs[i];
5569eb461aaSDag-Erling Smørgrav 			atom_r = PATIENCE(atom).pos_in_other;
5579eb461aaSDag-Erling Smørgrav 			debug("lcs[%u] = left[%u] = right[%u]\n", i,
5589eb461aaSDag-Erling Smørgrav 			      diff_atom_idx(left, atom), diff_atom_idx(right, atom_r));
5599eb461aaSDag-Erling Smørgrav 			left_idx = diff_atom_idx(left, atom);
5609eb461aaSDag-Erling Smørgrav 			right_idx = diff_atom_idx(right, atom_r);
5619eb461aaSDag-Erling Smørgrav 		} else {
5629eb461aaSDag-Erling Smørgrav 			/* There are no more identical lines until the end of
5639eb461aaSDag-Erling Smørgrav 			 * left and right. */
5649eb461aaSDag-Erling Smørgrav 			atom = NULL;
5659eb461aaSDag-Erling Smørgrav 			atom_r = NULL;
5669eb461aaSDag-Erling Smørgrav 			left_idx = left->atoms.len;
5679eb461aaSDag-Erling Smørgrav 			right_idx = right->atoms.len;
5689eb461aaSDag-Erling Smørgrav 		}
5699eb461aaSDag-Erling Smørgrav 
5709eb461aaSDag-Erling Smørgrav 		/* 'atom' (if not NULL) now marks an atom that matches on both
5719eb461aaSDag-Erling Smørgrav 		 * sides according to patience-diff (a common-unique identical
5729eb461aaSDag-Erling Smørgrav 		 * atom in both files).
5739eb461aaSDag-Erling Smørgrav 		 * Handle the section before and the atom itself; the section
5749eb461aaSDag-Erling Smørgrav 		 * after will be handled by the next loop iteration -- note that
5759eb461aaSDag-Erling Smørgrav 		 * i loops to last element + 1 ("i <= lcs_count"), so that there
5769eb461aaSDag-Erling Smørgrav 		 * will be another final iteration to pick up the last remaining
5779eb461aaSDag-Erling Smørgrav 		 * items after the last LCS atom.
5789eb461aaSDag-Erling Smørgrav 		 */
5799eb461aaSDag-Erling Smørgrav 
5809eb461aaSDag-Erling Smørgrav 		debug("iteration %u  left_pos %u  left_idx %u"
5819eb461aaSDag-Erling Smørgrav 		      "  right_pos %u  right_idx %u\n",
5829eb461aaSDag-Erling Smørgrav 		      i, left_pos, left_idx, right_pos, right_idx);
5839eb461aaSDag-Erling Smørgrav 
5849eb461aaSDag-Erling Smørgrav 		/* Section before the matching atom */
5859eb461aaSDag-Erling Smørgrav 		struct diff_atom *left_atom = &left->atoms.head[left_pos];
5869eb461aaSDag-Erling Smørgrav 		unsigned int left_section_len = left_idx - left_pos;
5879eb461aaSDag-Erling Smørgrav 
5889eb461aaSDag-Erling Smørgrav 		struct diff_atom *right_atom = &(right->atoms.head[right_pos]);
5899eb461aaSDag-Erling Smørgrav 		unsigned int right_section_len = right_idx - right_pos;
5909eb461aaSDag-Erling Smørgrav 
5919eb461aaSDag-Erling Smørgrav 		if (left_section_len && right_section_len) {
5929eb461aaSDag-Erling Smørgrav 			/* Record an unsolved chunk, the caller will apply
5939eb461aaSDag-Erling Smørgrav 			 * inner_algo() on this chunk. */
5949eb461aaSDag-Erling Smørgrav 			if (!diff_state_add_chunk(state, false,
5959eb461aaSDag-Erling Smørgrav 						  left_atom, left_section_len,
5969eb461aaSDag-Erling Smørgrav 						  right_atom,
5979eb461aaSDag-Erling Smørgrav 						  right_section_len))
5989eb461aaSDag-Erling Smørgrav 				goto free_and_exit;
5999eb461aaSDag-Erling Smørgrav 		} else if (left_section_len && !right_section_len) {
6009eb461aaSDag-Erling Smørgrav 			/* Only left atoms and none on the right, they form a
6019eb461aaSDag-Erling Smørgrav 			 * "minus" chunk, then. */
6029eb461aaSDag-Erling Smørgrav 			if (!diff_state_add_chunk(state, true,
6039eb461aaSDag-Erling Smørgrav 						  left_atom, left_section_len,
6049eb461aaSDag-Erling Smørgrav 						  right_atom, 0))
6059eb461aaSDag-Erling Smørgrav 				goto free_and_exit;
6069eb461aaSDag-Erling Smørgrav 		} else if (!left_section_len && right_section_len) {
6079eb461aaSDag-Erling Smørgrav 			/* No left atoms, only atoms on the right, they form a
6089eb461aaSDag-Erling Smørgrav 			 * "plus" chunk, then. */
6099eb461aaSDag-Erling Smørgrav 			if (!diff_state_add_chunk(state, true,
6109eb461aaSDag-Erling Smørgrav 						  left_atom, 0,
6119eb461aaSDag-Erling Smørgrav 						  right_atom, right_section_len))
6129eb461aaSDag-Erling Smørgrav 				goto free_and_exit;
6139eb461aaSDag-Erling Smørgrav 		}
6149eb461aaSDag-Erling Smørgrav 		/* else: left_section_len == 0 and right_section_len == 0, i.e.
6159eb461aaSDag-Erling Smørgrav 		 * nothing here. */
6169eb461aaSDag-Erling Smørgrav 
6179eb461aaSDag-Erling Smørgrav 		/* The atom found to match on both sides forms a chunk of equals
6189eb461aaSDag-Erling Smørgrav 		 * on each side. In the very last iteration of this loop, there
6199eb461aaSDag-Erling Smørgrav 		 * is no matching atom, we were just cleaning out the remaining
6209eb461aaSDag-Erling Smørgrav 		 * lines. */
6219eb461aaSDag-Erling Smørgrav 		if (atom) {
6229eb461aaSDag-Erling Smørgrav 			void *ok;
6239eb461aaSDag-Erling Smørgrav 			ok = diff_state_add_chunk(state, true,
6249eb461aaSDag-Erling Smørgrav 						  atom, 1,
6259eb461aaSDag-Erling Smørgrav 						  PATIENCE(atom).pos_in_other, 1);
6269eb461aaSDag-Erling Smørgrav 			if (!ok)
6279eb461aaSDag-Erling Smørgrav 				goto free_and_exit;
6289eb461aaSDag-Erling Smørgrav 		}
6299eb461aaSDag-Erling Smørgrav 		left_pos = left_idx + 1;
6309eb461aaSDag-Erling Smørgrav 		right_pos = right_idx + 1;
6319eb461aaSDag-Erling Smørgrav 		debug("end of iteration %u  left_pos %u  left_idx %u"
6329eb461aaSDag-Erling Smørgrav 		      "  right_pos %u  right_idx %u\n",
6339eb461aaSDag-Erling Smørgrav 		      i, left_pos, left_idx, right_pos, right_idx);
6349eb461aaSDag-Erling Smørgrav 	}
6359eb461aaSDag-Erling Smørgrav 	debug("** END %s\n", __func__);
6369eb461aaSDag-Erling Smørgrav 
6379eb461aaSDag-Erling Smørgrav 	rc = DIFF_RC_OK;
6389eb461aaSDag-Erling Smørgrav 
6399eb461aaSDag-Erling Smørgrav free_and_exit:
6409eb461aaSDag-Erling Smørgrav 	left->root->current = NULL;
6419eb461aaSDag-Erling Smørgrav 	right->root->current = NULL;
6429eb461aaSDag-Erling Smørgrav 	free(atom_patience_left);
6439eb461aaSDag-Erling Smørgrav 	free(atom_patience_right);
6449eb461aaSDag-Erling Smørgrav 	if (lcs)
6459eb461aaSDag-Erling Smørgrav 		free(lcs);
6469eb461aaSDag-Erling Smørgrav 	return rc;
6479eb461aaSDag-Erling Smørgrav }
648