Fossil SCM
More compact representation of a left/right rewrite on side-by-side diffs.
Commit
233c4975a82cf895c49794deedbd989256c87fc7
Parent
52db049b8922fae…
1 file changed
+42
-12
+42
-12
| --- src/diff.c | ||
| +++ src/diff.c | ||
| @@ -1043,13 +1043,14 @@ | ||
| 1043 | 1043 | ** |
| 1044 | 1044 | ** The return value is a buffer of unsigned characters, obtained from |
| 1045 | 1045 | ** fossil_malloc(). (The caller needs to free the return value using |
| 1046 | 1046 | ** fossil_free().) Entries in the returned array have values as follows: |
| 1047 | 1047 | ** |
| 1048 | -** 1. Delete the next line of pLeft. | |
| 1049 | -** 2. Insert the next line of pRight. | |
| 1050 | -** 3... The next line of pLeft changes into the next line of pRight. | |
| 1048 | +** 1. Delete the next line of pLeft. | |
| 1049 | +** 2. Insert the next line of pRight. | |
| 1050 | +** 3. The next line of pLeft changes into the next line of pRight. | |
| 1051 | +** 4. Delete one line from pLeft and add one line to pRight. | |
| 1051 | 1052 | ** |
| 1052 | 1053 | ** Values larger than three indicate better matches. |
| 1053 | 1054 | ** |
| 1054 | 1055 | ** The length of the returned array will be just large enough to cause |
| 1055 | 1056 | ** all elements of pLeft and pRight to be consumed. |
| @@ -1068,10 +1069,11 @@ | ||
| 1068 | 1069 | int *a; /* One row of the Wagner matrix */ |
| 1069 | 1070 | int *pToFree; /* Space that needs to be freed */ |
| 1070 | 1071 | unsigned char *aM; /* Wagner result matrix */ |
| 1071 | 1072 | int nMatch, iMatch; /* Number of matching lines and match score */ |
| 1072 | 1073 | int mnLen; /* MIN(nLeft, nRight) */ |
| 1074 | + int mxLen; /* MAX(nLeft, nRight) */ | |
| 1073 | 1075 | int aBuf[100]; /* Stack space for a[] if nRight not to big */ |
| 1074 | 1076 | |
| 1075 | 1077 | aM = fossil_malloc( (nLeft+1)*(nRight+1) ); |
| 1076 | 1078 | if( nLeft==0 ){ |
| 1077 | 1079 | memset(aM, 2, nRight); |
| @@ -1082,13 +1084,15 @@ | ||
| 1082 | 1084 | return aM; |
| 1083 | 1085 | } |
| 1084 | 1086 | |
| 1085 | 1087 | /* This algorithm is O(N**2). So if N is too big, bail out with a |
| 1086 | 1088 | ** simple (but stupid and ugly) result that doesn't take too long. */ |
| 1089 | + mnLen = nLeft<nRight ? nLeft : nRight; | |
| 1087 | 1090 | if( nLeft*nRight>100000 ){ |
| 1088 | - memset(aM, 2, nRight); | |
| 1089 | - memset(aM+nRight, 1, nLeft); | |
| 1091 | + memset(aM, 4, mnLen); | |
| 1092 | + if( nLeft>mnLen ) memset(aM+mnLen, 1, nLeft-mnLen); | |
| 1093 | + if( nRight>mnLen ) memset(aM+mnLen, 2, nRight-mnLen); | |
| 1090 | 1094 | return aM; |
| 1091 | 1095 | } |
| 1092 | 1096 | |
| 1093 | 1097 | if( nRight < (sizeof(aBuf)/sizeof(aBuf[0]))-1 ){ |
| 1094 | 1098 | pToFree = 0; |
| @@ -1131,24 +1135,26 @@ | ||
| 1131 | 1135 | i = nRight; |
| 1132 | 1136 | j = nLeft; |
| 1133 | 1137 | k = (nRight+1)*(nLeft+1)-1; |
| 1134 | 1138 | nMatch = iMatch = 0; |
| 1135 | 1139 | while( i+j>0 ){ |
| 1136 | - unsigned char c = aM[k--]; | |
| 1140 | + unsigned char c = aM[k]; | |
| 1137 | 1141 | if( c>=3 ){ |
| 1138 | 1142 | assert( i>0 && j>0 ); |
| 1139 | 1143 | i--; |
| 1140 | 1144 | j--; |
| 1141 | 1145 | nMatch++; |
| 1142 | 1146 | iMatch += (c>>2); |
| 1147 | + aM[k] = 3; | |
| 1143 | 1148 | }else if( c==2 ){ |
| 1144 | 1149 | assert( i>0 ); |
| 1145 | 1150 | i--; |
| 1146 | 1151 | }else{ |
| 1147 | 1152 | assert( j>0 ); |
| 1148 | 1153 | j--; |
| 1149 | 1154 | } |
| 1155 | + k--; | |
| 1150 | 1156 | aM[k] = aM[j*(nRight+1)+i]; |
| 1151 | 1157 | } |
| 1152 | 1158 | k++; |
| 1153 | 1159 | i = (nRight+1)*(nLeft+1) - k; |
| 1154 | 1160 | memmove(aM, &aM[k], i); |
| @@ -1161,14 +1167,15 @@ | ||
| 1161 | 1167 | ** by all of the left side deleted. |
| 1162 | 1168 | ** |
| 1163 | 1169 | ** The coefficients for conditions (1) and (2) above are determined by |
| 1164 | 1170 | ** experimentation. |
| 1165 | 1171 | */ |
| 1166 | - mnLen = nLeft>nRight ? nLeft : nRight; | |
| 1167 | - if( i*4>mnLen*5 && (nMatch==0 || iMatch/nMatch>15) ){ | |
| 1168 | - memset(aM, 2, nRight); | |
| 1169 | - memset(aM+nRight, 1, nLeft); | |
| 1172 | + mxLen = nLeft>nRight ? nLeft : nRight; | |
| 1173 | + if( i*4>mxLen*5 && (nMatch==0 || iMatch/nMatch>15) ){ | |
| 1174 | + memset(aM, 4, mnLen); | |
| 1175 | + if( nLeft>mnLen ) memset(aM+mnLen, 1, nLeft-mnLen); | |
| 1176 | + if( nRight>mnLen ) memset(aM+mnLen, 2, nRight-mnLen); | |
| 1170 | 1177 | } |
| 1171 | 1178 | |
| 1172 | 1179 | /* Return the result */ |
| 1173 | 1180 | fossil_free(pToFree); |
| 1174 | 1181 | return aM; |
| @@ -1302,10 +1309,11 @@ | ||
| 1302 | 1309 | } |
| 1303 | 1310 | |
| 1304 | 1311 | alignment = sbsAlignment(&A[a], ma, &B[b], mb); |
| 1305 | 1312 | for(j=0; ma+mb>0; j++){ |
| 1306 | 1313 | if( alignment[j]==1 ){ |
| 1314 | + /* Delete one line from the left */ | |
| 1307 | 1315 | s.n = 0; |
| 1308 | 1316 | sbsWriteLineno(&s, a); |
| 1309 | 1317 | s.iStart = 0; |
| 1310 | 1318 | s.zStart = "<span class=\"diffrm\">"; |
| 1311 | 1319 | s.iEnd = s.width; |
| @@ -1317,20 +1325,22 @@ | ||
| 1317 | 1325 | } |
| 1318 | 1326 | blob_append(pOut, s.zLine, s.n); |
| 1319 | 1327 | assert( ma>0 ); |
| 1320 | 1328 | ma--; |
| 1321 | 1329 | a++; |
| 1322 | - }else if( alignment[j]>=3 ){ | |
| 1330 | + }else if( alignment[j]==3 ){ | |
| 1331 | + /* The left line is changed into the right line */ | |
| 1323 | 1332 | s.n = 0; |
| 1324 | 1333 | sbsWriteLineChange(&s, &A[a], a, &B[b], b); |
| 1325 | 1334 | blob_append(pOut, s.zLine, s.n); |
| 1326 | 1335 | assert( ma>0 && mb>0 ); |
| 1327 | 1336 | ma--; |
| 1328 | 1337 | mb--; |
| 1329 | 1338 | a++; |
| 1330 | 1339 | b++; |
| 1331 | - }else{ | |
| 1340 | + }else if( alignment[j]==2 ){ | |
| 1341 | + /* Insert one line on the right */ | |
| 1332 | 1342 | s.n = 0; |
| 1333 | 1343 | sbsWriteSpace(&s, width + 7); |
| 1334 | 1344 | if( escHtml ){ |
| 1335 | 1345 | sbsWrite(&s, " > ", 6); |
| 1336 | 1346 | }else{ |
| @@ -1343,11 +1353,31 @@ | ||
| 1343 | 1353 | sbsWriteText(&s, &B[b], SBS_NEWLINE); |
| 1344 | 1354 | blob_append(pOut, s.zLine, s.n); |
| 1345 | 1355 | assert( mb>0 ); |
| 1346 | 1356 | mb--; |
| 1347 | 1357 | b++; |
| 1358 | + }else{ | |
| 1359 | + /* Delete from the left and insert on the right */ | |
| 1360 | + s.n = 0; | |
| 1361 | + sbsWriteLineno(&s, a); | |
| 1362 | + s.iStart = 0; | |
| 1363 | + s.zStart = "<span class=\"diffrm\">"; | |
| 1364 | + s.iEnd = s.width; | |
| 1365 | + sbsWriteText(&s, &A[a], SBS_PAD); | |
| 1366 | + sbsWrite(&s, " | ", 3); | |
| 1367 | + sbsWriteLineno(&s, b); | |
| 1368 | + s.iStart = 0; | |
| 1369 | + s.zStart = "<span class=\"diffadd\">"; | |
| 1370 | + s.iEnd = s.width; | |
| 1371 | + sbsWriteText(&s, &B[b], SBS_NEWLINE); | |
| 1372 | + blob_append(pOut, s.zLine, s.n); | |
| 1373 | + ma--; | |
| 1374 | + mb--; | |
| 1375 | + a++; | |
| 1376 | + b++; | |
| 1348 | 1377 | } |
| 1378 | + | |
| 1349 | 1379 | } |
| 1350 | 1380 | fossil_free(alignment); |
| 1351 | 1381 | if( i<nr-1 ){ |
| 1352 | 1382 | m = R[r+i*3+3]; |
| 1353 | 1383 | for(j=0; j<m; j++){ |
| 1354 | 1384 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -1043,13 +1043,14 @@ | |
| 1043 | ** |
| 1044 | ** The return value is a buffer of unsigned characters, obtained from |
| 1045 | ** fossil_malloc(). (The caller needs to free the return value using |
| 1046 | ** fossil_free().) Entries in the returned array have values as follows: |
| 1047 | ** |
| 1048 | ** 1. Delete the next line of pLeft. |
| 1049 | ** 2. Insert the next line of pRight. |
| 1050 | ** 3... The next line of pLeft changes into the next line of pRight. |
| 1051 | ** |
| 1052 | ** Values larger than three indicate better matches. |
| 1053 | ** |
| 1054 | ** The length of the returned array will be just large enough to cause |
| 1055 | ** all elements of pLeft and pRight to be consumed. |
| @@ -1068,10 +1069,11 @@ | |
| 1068 | int *a; /* One row of the Wagner matrix */ |
| 1069 | int *pToFree; /* Space that needs to be freed */ |
| 1070 | unsigned char *aM; /* Wagner result matrix */ |
| 1071 | int nMatch, iMatch; /* Number of matching lines and match score */ |
| 1072 | int mnLen; /* MIN(nLeft, nRight) */ |
| 1073 | int aBuf[100]; /* Stack space for a[] if nRight not to big */ |
| 1074 | |
| 1075 | aM = fossil_malloc( (nLeft+1)*(nRight+1) ); |
| 1076 | if( nLeft==0 ){ |
| 1077 | memset(aM, 2, nRight); |
| @@ -1082,13 +1084,15 @@ | |
| 1082 | return aM; |
| 1083 | } |
| 1084 | |
| 1085 | /* This algorithm is O(N**2). So if N is too big, bail out with a |
| 1086 | ** simple (but stupid and ugly) result that doesn't take too long. */ |
| 1087 | if( nLeft*nRight>100000 ){ |
| 1088 | memset(aM, 2, nRight); |
| 1089 | memset(aM+nRight, 1, nLeft); |
| 1090 | return aM; |
| 1091 | } |
| 1092 | |
| 1093 | if( nRight < (sizeof(aBuf)/sizeof(aBuf[0]))-1 ){ |
| 1094 | pToFree = 0; |
| @@ -1131,24 +1135,26 @@ | |
| 1131 | i = nRight; |
| 1132 | j = nLeft; |
| 1133 | k = (nRight+1)*(nLeft+1)-1; |
| 1134 | nMatch = iMatch = 0; |
| 1135 | while( i+j>0 ){ |
| 1136 | unsigned char c = aM[k--]; |
| 1137 | if( c>=3 ){ |
| 1138 | assert( i>0 && j>0 ); |
| 1139 | i--; |
| 1140 | j--; |
| 1141 | nMatch++; |
| 1142 | iMatch += (c>>2); |
| 1143 | }else if( c==2 ){ |
| 1144 | assert( i>0 ); |
| 1145 | i--; |
| 1146 | }else{ |
| 1147 | assert( j>0 ); |
| 1148 | j--; |
| 1149 | } |
| 1150 | aM[k] = aM[j*(nRight+1)+i]; |
| 1151 | } |
| 1152 | k++; |
| 1153 | i = (nRight+1)*(nLeft+1) - k; |
| 1154 | memmove(aM, &aM[k], i); |
| @@ -1161,14 +1167,15 @@ | |
| 1161 | ** by all of the left side deleted. |
| 1162 | ** |
| 1163 | ** The coefficients for conditions (1) and (2) above are determined by |
| 1164 | ** experimentation. |
| 1165 | */ |
| 1166 | mnLen = nLeft>nRight ? nLeft : nRight; |
| 1167 | if( i*4>mnLen*5 && (nMatch==0 || iMatch/nMatch>15) ){ |
| 1168 | memset(aM, 2, nRight); |
| 1169 | memset(aM+nRight, 1, nLeft); |
| 1170 | } |
| 1171 | |
| 1172 | /* Return the result */ |
| 1173 | fossil_free(pToFree); |
| 1174 | return aM; |
| @@ -1302,10 +1309,11 @@ | |
| 1302 | } |
| 1303 | |
| 1304 | alignment = sbsAlignment(&A[a], ma, &B[b], mb); |
| 1305 | for(j=0; ma+mb>0; j++){ |
| 1306 | if( alignment[j]==1 ){ |
| 1307 | s.n = 0; |
| 1308 | sbsWriteLineno(&s, a); |
| 1309 | s.iStart = 0; |
| 1310 | s.zStart = "<span class=\"diffrm\">"; |
| 1311 | s.iEnd = s.width; |
| @@ -1317,20 +1325,22 @@ | |
| 1317 | } |
| 1318 | blob_append(pOut, s.zLine, s.n); |
| 1319 | assert( ma>0 ); |
| 1320 | ma--; |
| 1321 | a++; |
| 1322 | }else if( alignment[j]>=3 ){ |
| 1323 | s.n = 0; |
| 1324 | sbsWriteLineChange(&s, &A[a], a, &B[b], b); |
| 1325 | blob_append(pOut, s.zLine, s.n); |
| 1326 | assert( ma>0 && mb>0 ); |
| 1327 | ma--; |
| 1328 | mb--; |
| 1329 | a++; |
| 1330 | b++; |
| 1331 | }else{ |
| 1332 | s.n = 0; |
| 1333 | sbsWriteSpace(&s, width + 7); |
| 1334 | if( escHtml ){ |
| 1335 | sbsWrite(&s, " > ", 6); |
| 1336 | }else{ |
| @@ -1343,11 +1353,31 @@ | |
| 1343 | sbsWriteText(&s, &B[b], SBS_NEWLINE); |
| 1344 | blob_append(pOut, s.zLine, s.n); |
| 1345 | assert( mb>0 ); |
| 1346 | mb--; |
| 1347 | b++; |
| 1348 | } |
| 1349 | } |
| 1350 | fossil_free(alignment); |
| 1351 | if( i<nr-1 ){ |
| 1352 | m = R[r+i*3+3]; |
| 1353 | for(j=0; j<m; j++){ |
| 1354 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -1043,13 +1043,14 @@ | |
| 1043 | ** |
| 1044 | ** The return value is a buffer of unsigned characters, obtained from |
| 1045 | ** fossil_malloc(). (The caller needs to free the return value using |
| 1046 | ** fossil_free().) Entries in the returned array have values as follows: |
| 1047 | ** |
| 1048 | ** 1. Delete the next line of pLeft. |
| 1049 | ** 2. Insert the next line of pRight. |
| 1050 | ** 3. The next line of pLeft changes into the next line of pRight. |
| 1051 | ** 4. Delete one line from pLeft and add one line to pRight. |
| 1052 | ** |
| 1053 | ** Values larger than three indicate better matches. |
| 1054 | ** |
| 1055 | ** The length of the returned array will be just large enough to cause |
| 1056 | ** all elements of pLeft and pRight to be consumed. |
| @@ -1068,10 +1069,11 @@ | |
| 1069 | int *a; /* One row of the Wagner matrix */ |
| 1070 | int *pToFree; /* Space that needs to be freed */ |
| 1071 | unsigned char *aM; /* Wagner result matrix */ |
| 1072 | int nMatch, iMatch; /* Number of matching lines and match score */ |
| 1073 | int mnLen; /* MIN(nLeft, nRight) */ |
| 1074 | int mxLen; /* MAX(nLeft, nRight) */ |
| 1075 | int aBuf[100]; /* Stack space for a[] if nRight not to big */ |
| 1076 | |
| 1077 | aM = fossil_malloc( (nLeft+1)*(nRight+1) ); |
| 1078 | if( nLeft==0 ){ |
| 1079 | memset(aM, 2, nRight); |
| @@ -1082,13 +1084,15 @@ | |
| 1084 | return aM; |
| 1085 | } |
| 1086 | |
| 1087 | /* This algorithm is O(N**2). So if N is too big, bail out with a |
| 1088 | ** simple (but stupid and ugly) result that doesn't take too long. */ |
| 1089 | mnLen = nLeft<nRight ? nLeft : nRight; |
| 1090 | if( nLeft*nRight>100000 ){ |
| 1091 | memset(aM, 4, mnLen); |
| 1092 | if( nLeft>mnLen ) memset(aM+mnLen, 1, nLeft-mnLen); |
| 1093 | if( nRight>mnLen ) memset(aM+mnLen, 2, nRight-mnLen); |
| 1094 | return aM; |
| 1095 | } |
| 1096 | |
| 1097 | if( nRight < (sizeof(aBuf)/sizeof(aBuf[0]))-1 ){ |
| 1098 | pToFree = 0; |
| @@ -1131,24 +1135,26 @@ | |
| 1135 | i = nRight; |
| 1136 | j = nLeft; |
| 1137 | k = (nRight+1)*(nLeft+1)-1; |
| 1138 | nMatch = iMatch = 0; |
| 1139 | while( i+j>0 ){ |
| 1140 | unsigned char c = aM[k]; |
| 1141 | if( c>=3 ){ |
| 1142 | assert( i>0 && j>0 ); |
| 1143 | i--; |
| 1144 | j--; |
| 1145 | nMatch++; |
| 1146 | iMatch += (c>>2); |
| 1147 | aM[k] = 3; |
| 1148 | }else if( c==2 ){ |
| 1149 | assert( i>0 ); |
| 1150 | i--; |
| 1151 | }else{ |
| 1152 | assert( j>0 ); |
| 1153 | j--; |
| 1154 | } |
| 1155 | k--; |
| 1156 | aM[k] = aM[j*(nRight+1)+i]; |
| 1157 | } |
| 1158 | k++; |
| 1159 | i = (nRight+1)*(nLeft+1) - k; |
| 1160 | memmove(aM, &aM[k], i); |
| @@ -1161,14 +1167,15 @@ | |
| 1167 | ** by all of the left side deleted. |
| 1168 | ** |
| 1169 | ** The coefficients for conditions (1) and (2) above are determined by |
| 1170 | ** experimentation. |
| 1171 | */ |
| 1172 | mxLen = nLeft>nRight ? nLeft : nRight; |
| 1173 | if( i*4>mxLen*5 && (nMatch==0 || iMatch/nMatch>15) ){ |
| 1174 | memset(aM, 4, mnLen); |
| 1175 | if( nLeft>mnLen ) memset(aM+mnLen, 1, nLeft-mnLen); |
| 1176 | if( nRight>mnLen ) memset(aM+mnLen, 2, nRight-mnLen); |
| 1177 | } |
| 1178 | |
| 1179 | /* Return the result */ |
| 1180 | fossil_free(pToFree); |
| 1181 | return aM; |
| @@ -1302,10 +1309,11 @@ | |
| 1309 | } |
| 1310 | |
| 1311 | alignment = sbsAlignment(&A[a], ma, &B[b], mb); |
| 1312 | for(j=0; ma+mb>0; j++){ |
| 1313 | if( alignment[j]==1 ){ |
| 1314 | /* Delete one line from the left */ |
| 1315 | s.n = 0; |
| 1316 | sbsWriteLineno(&s, a); |
| 1317 | s.iStart = 0; |
| 1318 | s.zStart = "<span class=\"diffrm\">"; |
| 1319 | s.iEnd = s.width; |
| @@ -1317,20 +1325,22 @@ | |
| 1325 | } |
| 1326 | blob_append(pOut, s.zLine, s.n); |
| 1327 | assert( ma>0 ); |
| 1328 | ma--; |
| 1329 | a++; |
| 1330 | }else if( alignment[j]==3 ){ |
| 1331 | /* The left line is changed into the right line */ |
| 1332 | s.n = 0; |
| 1333 | sbsWriteLineChange(&s, &A[a], a, &B[b], b); |
| 1334 | blob_append(pOut, s.zLine, s.n); |
| 1335 | assert( ma>0 && mb>0 ); |
| 1336 | ma--; |
| 1337 | mb--; |
| 1338 | a++; |
| 1339 | b++; |
| 1340 | }else if( alignment[j]==2 ){ |
| 1341 | /* Insert one line on the right */ |
| 1342 | s.n = 0; |
| 1343 | sbsWriteSpace(&s, width + 7); |
| 1344 | if( escHtml ){ |
| 1345 | sbsWrite(&s, " > ", 6); |
| 1346 | }else{ |
| @@ -1343,11 +1353,31 @@ | |
| 1353 | sbsWriteText(&s, &B[b], SBS_NEWLINE); |
| 1354 | blob_append(pOut, s.zLine, s.n); |
| 1355 | assert( mb>0 ); |
| 1356 | mb--; |
| 1357 | b++; |
| 1358 | }else{ |
| 1359 | /* Delete from the left and insert on the right */ |
| 1360 | s.n = 0; |
| 1361 | sbsWriteLineno(&s, a); |
| 1362 | s.iStart = 0; |
| 1363 | s.zStart = "<span class=\"diffrm\">"; |
| 1364 | s.iEnd = s.width; |
| 1365 | sbsWriteText(&s, &A[a], SBS_PAD); |
| 1366 | sbsWrite(&s, " | ", 3); |
| 1367 | sbsWriteLineno(&s, b); |
| 1368 | s.iStart = 0; |
| 1369 | s.zStart = "<span class=\"diffadd\">"; |
| 1370 | s.iEnd = s.width; |
| 1371 | sbsWriteText(&s, &B[b], SBS_NEWLINE); |
| 1372 | blob_append(pOut, s.zLine, s.n); |
| 1373 | ma--; |
| 1374 | mb--; |
| 1375 | a++; |
| 1376 | b++; |
| 1377 | } |
| 1378 | |
| 1379 | } |
| 1380 | fossil_free(alignment); |
| 1381 | if( i<nr-1 ){ |
| 1382 | m = R[r+i*3+3]; |
| 1383 | for(j=0; j<m; j++){ |
| 1384 |