]>
Commit | Line | Data |
---|---|---|
f345b0a0 JH |
1 | /* |
2 | * Copyright (C) 2005 Junio C Hamano | |
3 | */ | |
4 | #include "cache.h" | |
5 | #include "diff.h" | |
6 | #include "diffcore.h" | |
7 | #include "delta.h" | |
8 | #include "count-delta.h" | |
9 | ||
10 | static int very_different(struct diff_filespec *src, | |
11 | struct diff_filespec *dst, | |
12 | int min_score) | |
13 | { | |
14 | /* dst is recorded as a modification of src. Are they so | |
15 | * different that we are better off recording this as a pair | |
16 | * of delete and create? min_score is the minimum amount of | |
17 | * new material that must exist in the dst and not in src for | |
18 | * the pair to be considered a complete rewrite, and recommended | |
19 | * to be set to a very high value, 99% or so. | |
20 | * | |
21 | * The value we return represents the amount of new material | |
22 | * that is in dst and not in src. We return 0 when we do not | |
23 | * want to get the filepair broken. | |
24 | */ | |
25 | void *delta; | |
26 | unsigned long delta_size, base_size; | |
27 | ||
28 | if (!S_ISREG(src->mode) || !S_ISREG(dst->mode)) | |
29 | return 0; /* leave symlink rename alone */ | |
30 | ||
31 | if (diff_populate_filespec(src, 1) || diff_populate_filespec(dst, 1)) | |
32 | return 0; /* error but caught downstream */ | |
33 | ||
34 | delta_size = ((src->size < dst->size) ? | |
35 | (dst->size - src->size) : (src->size - dst->size)); | |
36 | ||
37 | /* Notice that we use max of src and dst as the base size, | |
38 | * unlike rename similarity detection. This is so that we do | |
39 | * not mistake a large addition as a complete rewrite. | |
40 | */ | |
41 | base_size = ((src->size < dst->size) ? dst->size : src->size); | |
42 | ||
43 | /* | |
44 | * If file size difference is too big compared to the | |
45 | * base_size, we declare this a complete rewrite. | |
46 | */ | |
47 | if (base_size * min_score < delta_size * MAX_SCORE) | |
48 | return MAX_SCORE; | |
49 | ||
50 | if (diff_populate_filespec(src, 0) || diff_populate_filespec(dst, 0)) | |
51 | return 0; /* error but caught downstream */ | |
52 | ||
53 | delta = diff_delta(src->data, src->size, | |
54 | dst->data, dst->size, | |
55 | &delta_size); | |
56 | ||
57 | /* A delta that has a lot of literal additions would have | |
58 | * big delta_size no matter what else it does. | |
59 | */ | |
60 | if (base_size * min_score < delta_size * MAX_SCORE) | |
61 | return MAX_SCORE; | |
62 | ||
63 | /* Estimate the edit size by interpreting delta. */ | |
64 | delta_size = count_delta(delta, delta_size); | |
65 | free(delta); | |
66 | if (delta_size == UINT_MAX) | |
67 | return 0; /* error in delta computation */ | |
68 | ||
69 | if (base_size < delta_size) | |
70 | return MAX_SCORE; | |
71 | ||
72 | return delta_size * MAX_SCORE / base_size; | |
73 | } | |
74 | ||
75 | void diffcore_break(int min_score) | |
76 | { | |
77 | struct diff_queue_struct *q = &diff_queued_diff; | |
78 | struct diff_queue_struct outq; | |
79 | int i; | |
80 | ||
81 | if (!min_score) | |
82 | min_score = DEFAULT_BREAK_SCORE; | |
83 | ||
84 | outq.nr = outq.alloc = 0; | |
85 | outq.queue = NULL; | |
86 | ||
87 | for (i = 0; i < q->nr; i++) { | |
88 | struct diff_filepair *p = q->queue[i]; | |
89 | int score; | |
90 | ||
91 | /* We deal only with in-place edit of non directory. | |
92 | * We do not break anything else. | |
93 | */ | |
94 | if (DIFF_FILE_VALID(p->one) && DIFF_FILE_VALID(p->two) && | |
95 | !S_ISDIR(p->one->mode) && !S_ISDIR(p->two->mode) && | |
96 | !strcmp(p->one->path, p->two->path)) { | |
97 | score = very_different(p->one, p->two, min_score); | |
98 | if (min_score <= score) { | |
99 | /* Split this into delete and create */ | |
100 | struct diff_filespec *null_one, *null_two; | |
101 | struct diff_filepair *dp; | |
102 | ||
103 | /* deletion of one */ | |
104 | null_one = alloc_filespec(p->one->path); | |
105 | dp = diff_queue(&outq, p->one, null_one); | |
106 | dp->score = score; | |
107 | dp->broken_pair = 1; | |
108 | ||
109 | /* creation of two */ | |
110 | null_two = alloc_filespec(p->two->path); | |
111 | dp = diff_queue(&outq, null_two, p->two); | |
112 | dp->score = score; | |
113 | dp->broken_pair = 1; | |
114 | ||
115 | free(p); /* not diff_free_filepair(), we are | |
116 | * reusing one and two here. | |
117 | */ | |
118 | continue; | |
119 | } | |
120 | } | |
121 | diff_q(&outq, p); | |
122 | } | |
123 | free(q->queue); | |
124 | *q = outq; | |
125 | ||
126 | return; | |
127 | } |