comparison src/xdiff/xpatience.c @ 32174:f84e5db372ea v9.0.1418

patch 9.0.1418: the included xdiff code is a bit outdated Commit: https://github.com/vim/vim/commit/5fedb8a5ab7addb584728c89e809be190de992bf Author: Yee Cheng Chin <ychin.git@gmail.com> Date: Mon Mar 20 17:30:52 2023 +0000 patch 9.0.1418: the included xdiff code is a bit outdated Problem: The included xdiff code is a bit outdated. Solution: Sync with the latest git xdiff code. (Yee Cheng Chin, closes #12181)
author Bram Moolenaar <Bram@vim.org>
date Mon, 20 Mar 2023 18:45:04 +0100
parents d5142d87f898
children
comparison
equal deleted inserted replaced
32173:1d3bf14313b6 32174:f84e5db372ea
67 */ 67 */
68 unsigned anchor : 1; 68 unsigned anchor : 1;
69 } *entries, *first, *last; 69 } *entries, *first, *last;
70 /* were common records found? */ 70 /* were common records found? */
71 unsigned long has_matches; 71 unsigned long has_matches;
72 mmfile_t *file1, *file2;
73 xdfenv_t *env; 72 xdfenv_t *env;
74 xpparam_t const *xpp; 73 xpparam_t const *xpp;
75 }; 74 };
76 75
77 static int is_anchor(xpparam_t const *xpp, const char *line) 76 static int is_anchor(xpparam_t const *xpp, const char *line)
137 * parts, as previously non-unique lines can become unique when being 136 * parts, as previously non-unique lines can become unique when being
138 * restricted to a smaller part of the files. 137 * restricted to a smaller part of the files.
139 * 138 *
140 * It is assumed that env has been prepared using xdl_prepare(). 139 * It is assumed that env has been prepared using xdl_prepare().
141 */ 140 */
142 static int fill_hashmap(mmfile_t *file1, mmfile_t *file2, 141 static int fill_hashmap(xpparam_t const *xpp, xdfenv_t *env,
143 xpparam_t const *xpp, xdfenv_t *env,
144 struct hashmap *result, 142 struct hashmap *result,
145 int line1, int count1, int line2, int count2) 143 int line1, int count1, int line2, int count2)
146 { 144 {
147 result->file1 = file1;
148 result->file2 = file2;
149 result->xpp = xpp; 145 result->xpp = xpp;
150 result->env = env; 146 result->env = env;
151 147
152 /* We know exactly how large we want the hash map */ 148 /* We know exactly how large we want the hash map */
153 result->alloc = count1 * 2; 149 result->alloc = count1 * 2;
154 result->entries = (struct entry *) 150 if (!XDL_CALLOC_ARRAY(result->entries, result->alloc))
155 xdl_malloc(result->alloc * sizeof(struct entry));
156 if (!result->entries)
157 return -1; 151 return -1;
158 memset(result->entries, 0, result->alloc * sizeof(struct entry));
159 152
160 /* First, fill with entries from the first file */ 153 /* First, fill with entries from the first file */
161 while (count1--) 154 while (count1--)
162 insert_record(xpp, line1++, result, 1); 155 insert_record(xpp, line1++, result, 1);
163 156
196 * 189 *
197 * For efficiency, the sequences are kept in a list containing exactly one 190 * For efficiency, the sequences are kept in a list containing exactly one
198 * item per sequence length: the sequence with the smallest last 191 * item per sequence length: the sequence with the smallest last
199 * element (in terms of line2). 192 * element (in terms of line2).
200 */ 193 */
201 static struct entry *find_longest_common_sequence(struct hashmap *map) 194 static int find_longest_common_sequence(struct hashmap *map, struct entry **res)
202 { 195 {
203 struct entry **sequence = xdl_malloc(map->nr * sizeof(struct entry *)); 196 struct entry **sequence;
204 int longest = 0, i; 197 int longest = 0, i;
205 struct entry *entry; 198 struct entry *entry;
206 199
207 /* 200 /*
208 * If not -1, this entry in sequence must never be overridden. 201 * If not -1, this entry in sequence must never be overridden.
209 * Therefore, overriding entries before this has no effect, so 202 * Therefore, overriding entries before this has no effect, so
210 * do not do that either. 203 * do not do that either.
211 */ 204 */
212 int anchor_i = -1; 205 int anchor_i = -1;
213 206
214 // Added to silence Coverity. 207 if (!XDL_ALLOC_ARRAY(sequence, map->nr))
215 if (sequence == NULL) 208 return -1;
216 return map->first;
217 209
218 for (entry = map->first; entry; entry = entry->next) { 210 for (entry = map->first; entry; entry = entry->next) {
219 if (!entry->line2 || entry->line2 == NON_UNIQUE) 211 if (!entry->line2 || entry->line2 == NON_UNIQUE)
220 continue; 212 continue;
221 i = binary_search(sequence, longest, entry); 213 i = binary_search(sequence, longest, entry);
232 } 224 }
233 } 225 }
234 226
235 /* No common unique lines were found */ 227 /* No common unique lines were found */
236 if (!longest) { 228 if (!longest) {
229 *res = NULL;
237 xdl_free(sequence); 230 xdl_free(sequence);
238 return NULL; 231 return 0;
239 } 232 }
240 233
241 /* Iterate starting at the last element, adjusting the "next" members */ 234 /* Iterate starting at the last element, adjusting the "next" members */
242 entry = sequence[longest - 1]; 235 entry = sequence[longest - 1];
243 entry->next = NULL; 236 entry->next = NULL;
244 while (entry->previous) { 237 while (entry->previous) {
245 entry->previous->next = entry; 238 entry->previous->next = entry;
246 entry = entry->previous; 239 entry = entry->previous;
247 } 240 }
241 *res = entry;
248 xdl_free(sequence); 242 xdl_free(sequence);
249 return entry; 243 return 0;
250 } 244 }
251 245
252 static int match(struct hashmap *map, int line1, int line2) 246 static int match(struct hashmap *map, int line1, int line2)
253 { 247 {
254 xrecord_t *record1 = map->env->xdf1.recs[line1 - 1]; 248 xrecord_t *record1 = map->env->xdf1.recs[line1 - 1];
255 xrecord_t *record2 = map->env->xdf2.recs[line2 - 1]; 249 xrecord_t *record2 = map->env->xdf2.recs[line2 - 1];
256 return record1->ha == record2->ha; 250 return record1->ha == record2->ha;
257 } 251 }
258 252
259 static int patience_diff(mmfile_t *file1, mmfile_t *file2, 253 static int patience_diff(xpparam_t const *xpp, xdfenv_t *env,
260 xpparam_t const *xpp, xdfenv_t *env,
261 int line1, int count1, int line2, int count2); 254 int line1, int count1, int line2, int count2);
262 255
263 static int walk_common_sequence(struct hashmap *map, struct entry *first, 256 static int walk_common_sequence(struct hashmap *map, struct entry *first,
264 int line1, int count1, int line2, int count2) 257 int line1, int count1, int line2, int count2)
265 { 258 {
286 line2++; 279 line2++;
287 } 280 }
288 281
289 /* Recurse */ 282 /* Recurse */
290 if (next1 > line1 || next2 > line2) { 283 if (next1 > line1 || next2 > line2) {
291 if (patience_diff(map->file1, map->file2, 284 if (patience_diff(map->xpp, map->env,
292 map->xpp, map->env,
293 line1, next1 - line1, 285 line1, next1 - line1,
294 line2, next2 - line2)) 286 line2, next2 - line2))
295 return -1; 287 return -1;
296 } 288 }
297 289
326 * Recursively find the longest common sequence of unique lines, 318 * Recursively find the longest common sequence of unique lines,
327 * and if none was found, ask xdl_do_diff() to do the job. 319 * and if none was found, ask xdl_do_diff() to do the job.
328 * 320 *
329 * This function assumes that env was prepared with xdl_prepare_env(). 321 * This function assumes that env was prepared with xdl_prepare_env().
330 */ 322 */
331 static int patience_diff(mmfile_t *file1, mmfile_t *file2, 323 static int patience_diff(xpparam_t const *xpp, xdfenv_t *env,
332 xpparam_t const *xpp, xdfenv_t *env,
333 int line1, int count1, int line2, int count2) 324 int line1, int count1, int line2, int count2)
334 { 325 {
335 struct hashmap map; 326 struct hashmap map;
336 struct entry *first; 327 struct entry *first;
337 int result = 0; 328 int result = 0;
346 env->xdf1.rchg[line1++ - 1] = 1; 337 env->xdf1.rchg[line1++ - 1] = 1;
347 return 0; 338 return 0;
348 } 339 }
349 340
350 memset(&map, 0, sizeof(map)); 341 memset(&map, 0, sizeof(map));
351 if (fill_hashmap(file1, file2, xpp, env, &map, 342 if (fill_hashmap(xpp, env, &map,
352 line1, count1, line2, count2)) 343 line1, count1, line2, count2))
353 return -1; 344 return -1;
354 345
355 /* are there any matching lines at all? */ 346 /* are there any matching lines at all? */
356 if (!map.has_matches) { 347 if (!map.has_matches) {
360 env->xdf2.rchg[line2++ - 1] = 1; 351 env->xdf2.rchg[line2++ - 1] = 1;
361 xdl_free(map.entries); 352 xdl_free(map.entries);
362 return 0; 353 return 0;
363 } 354 }
364 355
365 first = find_longest_common_sequence(&map); 356 result = find_longest_common_sequence(&map, &first);
357 if (result)
358 goto out;
366 if (first) 359 if (first)
367 result = walk_common_sequence(&map, first, 360 result = walk_common_sequence(&map, first,
368 line1, count1, line2, count2); 361 line1, count1, line2, count2);
369 else 362 else
370 result = fall_back_to_classic_diff(&map, 363 result = fall_back_to_classic_diff(&map,
371 line1, count1, line2, count2); 364 line1, count1, line2, count2);
372 365 out:
373 xdl_free(map.entries); 366 xdl_free(map.entries);
374 return result; 367 return result;
375 } 368 }
376 369
377 int xdl_do_patience_diff(mmfile_t *file1, mmfile_t *file2, 370 int xdl_do_patience_diff(xpparam_t const *xpp, xdfenv_t *env)
378 xpparam_t const *xpp, xdfenv_t *env) 371 {
379 { 372 return patience_diff(xpp, env, 1, env->xdf1.nrec, 1, env->xdf2.nrec);
380 if (xdl_prepare_env(file1, file2, xpp, env) < 0) 373 }
381 return -1;
382
383 /* environment is cleaned up in xdl_diff() */
384 return patience_diff(file1, file2, xpp, env,
385 1, env->xdf1.nrec, 1, env->xdf2.nrec);
386 }