mergeinfo.c (302408) | mergeinfo.c (362181) |
---|---|
1/* 2 * mergeinfo.c: Mergeinfo parsing and handling 3 * 4 * ==================================================================== 5 * Licensed to the Apache Software Foundation (ASF) under one 6 * or more contributor license agreements. See the NOTICE file 7 * distributed with this work for additional information 8 * regarding copyright ownership. The ASF licenses this file --- 27 unchanged lines hidden (view full) --- 36#include "private/svn_mergeinfo_private.h" 37#include "private/svn_sorts_private.h" 38#include "private/svn_string_private.h" 39#include "private/svn_subr_private.h" 40#include "svn_private_config.h" 41#include "svn_hash.h" 42#include "private/svn_dep_compat.h" 43 | 1/* 2 * mergeinfo.c: Mergeinfo parsing and handling 3 * 4 * ==================================================================== 5 * Licensed to the Apache Software Foundation (ASF) under one 6 * or more contributor license agreements. See the NOTICE file 7 * distributed with this work for additional information 8 * regarding copyright ownership. The ASF licenses this file --- 27 unchanged lines hidden (view full) --- 36#include "private/svn_mergeinfo_private.h" 37#include "private/svn_sorts_private.h" 38#include "private/svn_string_private.h" 39#include "private/svn_subr_private.h" 40#include "svn_private_config.h" 41#include "svn_hash.h" 42#include "private/svn_dep_compat.h" 43 |
44/* Return TRUE iff the forward revision range FIRST wholly contains the 45 * forward revision range SECOND and (if CONSIDER_INHERITANCE is TRUE) has 46 * the same inheritability. */ 47static svn_error_t * 48range_contains(svn_boolean_t *result, 49 const svn_merge_range_t *first, const svn_merge_range_t *second, 50 svn_boolean_t consider_inheritance); 51 52 |
|
44/* Attempt to combine two ranges, IN1 and IN2. If they are adjacent or 45 overlapping, and their inheritability allows them to be combined, put 46 the result in OUTPUT and return TRUE, otherwise return FALSE. 47 48 CONSIDER_INHERITANCE determines how to account for the inheritability 49 of IN1 and IN2 when trying to combine ranges. If ranges with different 50 inheritability are combined (CONSIDER_INHERITANCE must be FALSE for this 51 to happen) the result is inheritable. If both ranges are inheritable the --- 206 unchanged lines hidden (view full) --- 258 lastrange = NULL; 259 260 if (!lastrange) 261 { 262 /* No *LASTRANGE so push NEW_RANGE onto RANGELIST and we are done. */ 263 APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = 264 svn_merge_range_dup(new_range, result_pool); 265 } | 53/* Attempt to combine two ranges, IN1 and IN2. If they are adjacent or 54 overlapping, and their inheritability allows them to be combined, put 55 the result in OUTPUT and return TRUE, otherwise return FALSE. 56 57 CONSIDER_INHERITANCE determines how to account for the inheritability 58 of IN1 and IN2 when trying to combine ranges. If ranges with different 59 inheritability are combined (CONSIDER_INHERITANCE must be FALSE for this 60 to happen) the result is inheritable. If both ranges are inheritable the --- 206 unchanged lines hidden (view full) --- 267 lastrange = NULL; 268 269 if (!lastrange) 270 { 271 /* No *LASTRANGE so push NEW_RANGE onto RANGELIST and we are done. */ 272 APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = 273 svn_merge_range_dup(new_range, result_pool); 274 } |
275 else if (combine_ranges(&combined_range, lastrange, new_range, 276 consider_inheritance)) 277 { 278 *lastrange = combined_range; 279 } |
|
266 else if (!consider_inheritance) 267 { 268 /* We are not considering inheritance so we can merge intersecting 269 ranges of different inheritability. Of course if the ranges 270 don't intersect at all we simply push NEW_RANGE onto RANGELIST. */ | 280 else if (!consider_inheritance) 281 { 282 /* We are not considering inheritance so we can merge intersecting 283 ranges of different inheritability. Of course if the ranges 284 don't intersect at all we simply push NEW_RANGE onto RANGELIST. */ |
271 if (combine_ranges(&combined_range, lastrange, new_range, FALSE)) 272 { 273 *lastrange = combined_range; 274 } 275 else 276 { 277 APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = | 285 APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = |
278 svn_merge_range_dup(new_range, result_pool); | 286 svn_merge_range_dup(new_range, result_pool); |
279 } | |
280 } 281 else /* Considering inheritance */ 282 { | 287 } 288 else /* Considering inheritance */ 289 { |
283 if (combine_ranges(&combined_range, lastrange, new_range, TRUE)) | 290 /* If we are here then the ranges either don't intersect or do 291 intersect but have differing inheritability. Check for the 292 first case as that is easy to handle. */ 293 intersection_type_t intersection_type; 294 svn_boolean_t sorted = FALSE; 295 296 SVN_ERR(get_type_of_intersection(new_range, lastrange, 297 &intersection_type)); 298 299 switch (intersection_type) |
284 { | 300 { |
285 /* Even when considering inheritance two intersection ranges 286 of the same inheritability can simply be combined. */ 287 *lastrange = combined_range; 288 } 289 else 290 { 291 /* If we are here then the ranges either don't intersect or do 292 intersect but have differing inheritability. Check for the 293 first case as that is easy to handle. */ 294 intersection_type_t intersection_type; 295 svn_boolean_t sorted = FALSE; | 301 case svn__no_intersection: 302 /* NEW_RANGE and *LASTRANGE *really* don't intersect so 303 just push NEW_RANGE onto RANGELIST. */ 304 APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = 305 svn_merge_range_dup(new_range, result_pool); 306 sorted = (svn_sort_compare_ranges(&lastrange, 307 &new_range) < 0); 308 break; |
296 | 309 |
297 SVN_ERR(get_type_of_intersection(new_range, lastrange, 298 &intersection_type)); | 310 case svn__equal_intersection: 311 /* They range are equal so all we do is force the 312 inheritability of lastrange to true. */ 313 lastrange->inheritable = TRUE; 314 sorted = TRUE; 315 break; |
299 | 316 |
300 switch (intersection_type) | 317 case svn__adjoining_intersection: 318 /* They adjoin but don't overlap so just push NEW_RANGE 319 onto RANGELIST. */ 320 APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = 321 svn_merge_range_dup(new_range, result_pool); 322 sorted = (svn_sort_compare_ranges(&lastrange, 323 &new_range) < 0); 324 break; 325 326 case svn__overlapping_intersection: 327 /* They ranges overlap but neither is a proper subset of 328 the other. We'll end up pusing two new ranges onto 329 RANGELIST, the intersecting part and the part unique to 330 NEW_RANGE.*/ |
301 { | 331 { |
302 case svn__no_intersection: 303 /* NEW_RANGE and *LASTRANGE *really* don't intersect so 304 just push NEW_RANGE onto RANGELIST. */ 305 APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = 306 svn_merge_range_dup(new_range, result_pool); 307 sorted = (svn_sort_compare_ranges(&lastrange, 308 &new_range) < 0); 309 break; | 332 svn_merge_range_t *r1 = svn_merge_range_dup(lastrange, 333 result_pool); 334 svn_merge_range_t *r2 = svn_merge_range_dup(new_range, 335 result_pool); |
310 | 336 |
311 case svn__equal_intersection: 312 /* They range are equal so all we do is force the 313 inheritability of lastrange to true. */ 314 lastrange->inheritable = TRUE; 315 sorted = TRUE; 316 break; | 337 /* Pop off *LASTRANGE to make our manipulations 338 easier. */ 339 apr_array_pop(rangelist); |
317 | 340 |
318 case svn__adjoining_intersection: 319 /* They adjoin but don't overlap so just push NEW_RANGE 320 onto RANGELIST. */ 321 APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = 322 svn_merge_range_dup(new_range, result_pool); 323 sorted = (svn_sort_compare_ranges(&lastrange, 324 &new_range) < 0); 325 break; 326 327 case svn__overlapping_intersection: 328 /* They ranges overlap but neither is a proper subset of 329 the other. We'll end up pusing two new ranges onto 330 RANGELIST, the intersecting part and the part unique to 331 NEW_RANGE.*/ | 341 /* Ensure R1 is the older range. */ 342 if (r2->start < r1->start) |
332 { | 343 { |
333 svn_merge_range_t *r1 = svn_merge_range_dup(lastrange, 334 result_pool); 335 svn_merge_range_t *r2 = svn_merge_range_dup(new_range, 336 result_pool); | 344 /* Swap R1 and R2. */ 345 *r2 = *r1; 346 *r1 = *new_range; 347 } |
337 | 348 |
338 /* Pop off *LASTRANGE to make our manipulations 339 easier. */ 340 apr_array_pop(rangelist); | 349 /* Absorb the intersecting ranges into the 350 inheritable range. */ 351 if (r1->inheritable) 352 r2->start = r1->end; 353 else 354 r1->end = r2->start; |
341 | 355 |
342 /* Ensure R1 is the older range. */ 343 if (r2->start < r1->start) 344 { 345 /* Swap R1 and R2. */ 346 *r2 = *r1; 347 *r1 = *new_range; 348 } | 356 /* Push everything back onto RANGELIST. */ 357 APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r1; 358 sorted = (svn_sort_compare_ranges(&lastrange, 359 &r1) < 0); 360 APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r2; 361 if (sorted) 362 sorted = (svn_sort_compare_ranges(&r1, &r2) < 0); 363 break; 364 } |
349 | 365 |
350 /* Absorb the intersecting ranges into the 351 inheritable range. */ 352 if (r1->inheritable) 353 r2->start = r1->end; 354 else 355 r1->end = r2->start; | 366 default: /* svn__proper_subset_intersection */ 367 { 368 /* One range is a proper subset of the other. */ 369 svn_merge_range_t *r1 = svn_merge_range_dup(lastrange, 370 result_pool); 371 svn_merge_range_t *r2 = svn_merge_range_dup(new_range, 372 result_pool); 373 svn_merge_range_t *r3 = NULL; |
356 | 374 |
357 /* Push everything back onto RANGELIST. */ 358 APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r1; 359 sorted = (svn_sort_compare_ranges(&lastrange, 360 &r1) < 0); 361 APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r2; 362 if (sorted) 363 sorted = (svn_sort_compare_ranges(&r1, &r2) < 0); 364 break; | 375 /* Pop off *LASTRANGE to make our manipulations 376 easier. */ 377 apr_array_pop(rangelist); 378 379 /* Ensure R1 is the superset. */ 380 if (r2->start < r1->start || r2->end > r1->end) 381 { 382 /* Swap R1 and R2. */ 383 *r2 = *r1; 384 *r1 = *new_range; |
365 } 366 | 385 } 386 |
367 default: /* svn__proper_subset_intersection */ | 387 if (r1->inheritable) |
368 { | 388 { |
369 /* One range is a proper subset of the other. */ 370 svn_merge_range_t *r1 = svn_merge_range_dup(lastrange, 371 result_pool); 372 svn_merge_range_t *r2 = svn_merge_range_dup(new_range, 373 result_pool); 374 svn_merge_range_t *r3 = NULL; | 389 /* The simple case: The superset is inheritable, so 390 just combine r1 and r2. */ 391 r1->start = MIN(r1->start, r2->start); 392 r1->end = MAX(r1->end, r2->end); 393 r2 = NULL; 394 } 395 else if (r1->start == r2->start) 396 { 397 svn_revnum_t tmp_revnum; |
375 | 398 |
376 /* Pop off *LASTRANGE to make our manipulations 377 easier. */ 378 apr_array_pop(rangelist); | 399 /* *LASTRANGE and NEW_RANGE share an end point. */ 400 tmp_revnum = r1->end; 401 r1->end = r2->end; 402 r2->inheritable = r1->inheritable; 403 r1->inheritable = TRUE; 404 r2->start = r1->end; 405 r2->end = tmp_revnum; 406 } 407 else if (r1->end == r2->end) 408 { 409 /* *LASTRANGE and NEW_RANGE share an end point. */ 410 r1->end = r2->start; 411 r2->inheritable = TRUE; 412 } 413 else 414 { 415 /* NEW_RANGE and *LASTRANGE share neither start 416 nor end points. */ 417 r3 = apr_pcalloc(result_pool, sizeof(*r3)); 418 r3->start = r2->end; 419 r3->end = r1->end; 420 r3->inheritable = r1->inheritable; 421 r2->inheritable = TRUE; 422 r1->end = r2->start; 423 } |
379 | 424 |
380 /* Ensure R1 is the superset. */ 381 if (r2->start < r1->start || r2->end > r1->end) | 425 /* Push everything back onto RANGELIST. */ 426 APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r1; 427 sorted = (svn_sort_compare_ranges(&lastrange, &r1) < 0); 428 if (r2) 429 { 430 APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r2; 431 if (sorted) 432 sorted = (svn_sort_compare_ranges(&r1, &r2) < 0); 433 } 434 if (r3) 435 { 436 APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r3; 437 if (sorted) |
382 { | 438 { |
383 /* Swap R1 and R2. */ 384 *r2 = *r1; 385 *r1 = *new_range; | 439 if (r2) 440 sorted = (svn_sort_compare_ranges(&r2, 441 &r3) < 0); 442 else 443 sorted = (svn_sort_compare_ranges(&r1, 444 &r3) < 0); |
386 } | 445 } |
387 388 if (r1->inheritable) 389 { 390 /* The simple case: The superset is inheritable, so 391 just combine r1 and r2. */ 392 r1->start = MIN(r1->start, r2->start); 393 r1->end = MAX(r1->end, r2->end); 394 r2 = NULL; 395 } 396 else if (r1->start == r2->start) 397 { 398 svn_revnum_t tmp_revnum; 399 400 /* *LASTRANGE and NEW_RANGE share an end point. */ 401 tmp_revnum = r1->end; 402 r1->end = r2->end; 403 r2->inheritable = r1->inheritable; 404 r1->inheritable = TRUE; 405 r2->start = r1->end; 406 r2->end = tmp_revnum; 407 } 408 else if (r1->end == r2->end) 409 { 410 /* *LASTRANGE and NEW_RANGE share an end point. */ 411 r1->end = r2->start; 412 r2->inheritable = TRUE; 413 } 414 else 415 { 416 /* NEW_RANGE and *LASTRANGE share neither start 417 nor end points. */ 418 r3 = apr_pcalloc(result_pool, sizeof(*r3)); 419 r3->start = r2->end; 420 r3->end = r1->end; 421 r3->inheritable = r1->inheritable; 422 r2->inheritable = TRUE; 423 r1->end = r2->start; 424 } 425 426 /* Push everything back onto RANGELIST. */ 427 APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r1; 428 sorted = (svn_sort_compare_ranges(&lastrange, &r1) < 0); 429 if (r2) 430 { 431 APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r2; 432 if (sorted) 433 sorted = (svn_sort_compare_ranges(&r1, &r2) < 0); 434 } 435 if (r3) 436 { 437 APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r3; 438 if (sorted) 439 { 440 if (r2) 441 sorted = (svn_sort_compare_ranges(&r2, 442 &r3) < 0); 443 else 444 sorted = (svn_sort_compare_ranges(&r1, 445 &r3) < 0); 446 } 447 } 448 break; | |
449 } | 446 } |
447 break; |
|
450 } | 448 } |
451 452 /* Some of the above cases might have put *RANGELIST out of 453 order, so re-sort.*/ 454 if (!sorted) 455 svn_sort__array(rangelist, svn_sort_compare_ranges); | |
456 } | 449 } |
450 451 /* Some of the above cases might have put *RANGELIST out of 452 order, so re-sort.*/ 453 if (!sorted) 454 svn_sort__array(rangelist, svn_sort_compare_ranges); |
|
457 } 458 459 return SVN_NO_ERROR; 460} 461 462/* Convert a single svn_merge_range_t *RANGE back into a string. */ | 455 } 456 457 return SVN_NO_ERROR; 458} 459 460/* Convert a single svn_merge_range_t *RANGE back into a string. */ |
463static char * 464range_to_string(const svn_merge_range_t *range, | 461static svn_error_t * 462range_to_string(char **s, 463 const svn_merge_range_t *range, |
465 apr_pool_t *pool) 466{ 467 const char *mark 468 = range->inheritable ? "" : SVN_MERGEINFO_NONINHERITABLE_STR; 469 470 if (range->start == range->end - 1) | 464 apr_pool_t *pool) 465{ 466 const char *mark 467 = range->inheritable ? "" : SVN_MERGEINFO_NONINHERITABLE_STR; 468 469 if (range->start == range->end - 1) |
471 return apr_psprintf(pool, "%ld%s", range->end, mark); | 470 *s = apr_psprintf(pool, "%ld%s", range->end, mark); |
472 else if (range->start - 1 == range->end) | 471 else if (range->start - 1 == range->end) |
473 return apr_psprintf(pool, "-%ld%s", range->start, mark); | 472 *s = apr_psprintf(pool, "-%ld%s", range->start, mark); |
474 else if (range->start < range->end) | 473 else if (range->start < range->end) |
475 return apr_psprintf(pool, "%ld-%ld%s", range->start + 1, range->end, mark); | 474 *s = apr_psprintf(pool, "%ld-%ld%s", range->start + 1, range->end, mark); 475 else if (range->start > range->end) 476 *s = apr_psprintf(pool, "%ld-%ld%s", range->start, range->end + 1, mark); |
476 else | 477 else |
477 return apr_psprintf(pool, "%ld-%ld%s", range->start, range->end + 1, mark); | 478 { 479 return svn_error_createf(SVN_ERR_ASSERTION_FAIL, NULL, 480 _("bad range {start=%ld,end=%ld,inheritable=%d}"), 481 range->start, range->end, range->inheritable); 482 } 483 484 return SVN_NO_ERROR; |
478} 479 | 485} 486 |
487/* Convert a single svn_merge_range_t *RANGE back into a string. */ 488static char * 489range_to_string_debug(const svn_merge_range_t *range, 490 apr_pool_t *pool) 491{ 492 svn_error_t *err; 493 char *s; 494 495 err = range_to_string(&s, range, pool); 496 if (err) 497 { 498 svn_error_clear(err); 499 s = apr_psprintf(pool, _("bad range {start=%ld,end=%ld,inheritable=%d}"), 500 range->start, range->end, range->inheritable); 501 } 502 return s; 503} 504 |
|
480/* Helper for svn_mergeinfo_parse() 481 Append revision ranges onto the array RANGELIST to represent the range 482 descriptions found in the string *INPUT. Read only as far as a newline 483 or the position END, whichever comes first. Set *INPUT to the position 484 after the last character of INPUT that was used. 485 486 revisionlist -> (revisionelement)(COMMA revisionelement)* 487 revisionrange -> REVISION "-" REVISION("*") --- 115 unchanged lines hidden (view full) --- 603{ 604 const char *s = str; 605 606 *rangelist = apr_array_make(result_pool, 1, sizeof(svn_merge_range_t *)); 607 SVN_ERR(parse_rangelist(&s, s + strlen(s), *rangelist, result_pool)); 608 return SVN_NO_ERROR; 609} 610 | 505/* Helper for svn_mergeinfo_parse() 506 Append revision ranges onto the array RANGELIST to represent the range 507 descriptions found in the string *INPUT. Read only as far as a newline 508 or the position END, whichever comes first. Set *INPUT to the position 509 after the last character of INPUT that was used. 510 511 revisionlist -> (revisionelement)(COMMA revisionelement)* 512 revisionrange -> REVISION "-" REVISION("*") --- 115 unchanged lines hidden (view full) --- 628{ 629 const char *s = str; 630 631 *rangelist = apr_array_make(result_pool, 1, sizeof(svn_merge_range_t *)); 632 SVN_ERR(parse_rangelist(&s, s + strlen(s), *rangelist, result_pool)); 633 return SVN_NO_ERROR; 634} 635 |
611/* Return TRUE, if all ranges in RANGELIST are in ascending order and do 612 * not overlap and are not adjacent. 613 * 614 * ### Can yield false negatives: ranges of differing inheritance are 615 * allowed to be adjacent. 616 * 617 * If this returns FALSE, you probaly want to qsort() the 618 * ranges and then call svn_rangelist__combine_adjacent_ranges(). 619 */ 620static svn_boolean_t 621is_rangelist_normalized(svn_rangelist_t *rangelist) | 636svn_boolean_t 637svn_rangelist__is_canonical(const svn_rangelist_t *rangelist) |
622{ 623 int i; 624 svn_merge_range_t **ranges = (svn_merge_range_t **)rangelist->elts; 625 | 638{ 639 int i; 640 svn_merge_range_t **ranges = (svn_merge_range_t **)rangelist->elts; 641 |
626 for (i = 0; i < rangelist->nelts-1; ++i) 627 if (ranges[i]->end >= ranges[i+1]->start) 628 return FALSE; | 642 /* Check for reversed and empty ranges */ 643 for (i = 0; i < rangelist->nelts; ++i) 644 { 645 if (ranges[i]->start >= ranges[i]->end) 646 return FALSE; 647 } |
629 | 648 |
649 /* Check for overlapping ranges */ 650 for (i = 0; i < rangelist->nelts - 1; ++i) 651 { 652 if (ranges[i]->end > ranges[i + 1]->start) 653 return FALSE; /* Overlapping range */ 654 else if (ranges[i]->end == ranges[i+1]->start 655 && ranges[i]->inheritable == ranges[i + 1]->inheritable) 656 { 657 return FALSE; /* Ranges should have been combined */ 658 } 659 } 660 |
|
630 return TRUE; 631} 632 | 661 return TRUE; 662} 663 |
664/* In-place combines adjacent ranges in a rangelist. 665 SCRATCH_POOL is just used for providing error messages. */ |
|
633svn_error_t * 634svn_rangelist__canonicalize(svn_rangelist_t *rangelist, 635 apr_pool_t *scratch_pool) 636{ | 666svn_error_t * 667svn_rangelist__canonicalize(svn_rangelist_t *rangelist, 668 apr_pool_t *scratch_pool) 669{ |
637 if (! is_rangelist_normalized(rangelist)) 638 { 639 svn_sort__array(rangelist, svn_sort_compare_ranges); 640 641 SVN_ERR(svn_rangelist__combine_adjacent_ranges(rangelist, scratch_pool)); 642 } 643 644 return SVN_NO_ERROR; 645} 646 647svn_error_t * 648svn_rangelist__combine_adjacent_ranges(svn_rangelist_t *rangelist, 649 apr_pool_t *scratch_pool) 650{ | |
651 int i; 652 svn_merge_range_t *range, *lastrange; 653 | 670 int i; 671 svn_merge_range_t *range, *lastrange; 672 |
673 if (svn_rangelist__is_canonical(rangelist)) 674 return SVN_NO_ERROR; /* Nothing to do */ 675 676 svn_sort__array(rangelist, svn_sort_compare_ranges); 677 |
|
654 lastrange = APR_ARRAY_IDX(rangelist, 0, svn_merge_range_t *); 655 656 for (i = 1; i < rangelist->nelts; i++) 657 { 658 range = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *); 659 if (lastrange->start <= range->end 660 && range->start <= lastrange->end) 661 { --- 4 unchanged lines hidden (view full) --- 666 if (range->start < lastrange->end 667 && range->inheritable != lastrange->inheritable) 668 { 669 return svn_error_createf(SVN_ERR_MERGEINFO_PARSE_ERROR, NULL, 670 _("Unable to parse overlapping " 671 "revision ranges '%s' and '%s' " 672 "with different inheritance " 673 "types"), | 678 lastrange = APR_ARRAY_IDX(rangelist, 0, svn_merge_range_t *); 679 680 for (i = 1; i < rangelist->nelts; i++) 681 { 682 range = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *); 683 if (lastrange->start <= range->end 684 && range->start <= lastrange->end) 685 { --- 4 unchanged lines hidden (view full) --- 690 if (range->start < lastrange->end 691 && range->inheritable != lastrange->inheritable) 692 { 693 return svn_error_createf(SVN_ERR_MERGEINFO_PARSE_ERROR, NULL, 694 _("Unable to parse overlapping " 695 "revision ranges '%s' and '%s' " 696 "with different inheritance " 697 "types"), |
674 range_to_string(lastrange, 675 scratch_pool), 676 range_to_string(range, 677 scratch_pool)); | 698 range_to_string_debug(lastrange, 699 scratch_pool), 700 range_to_string_debug(range, 701 scratch_pool)); |
678 } 679 680 /* Combine overlapping or adjacent ranges with the 681 same inheritability. */ 682 if (lastrange->inheritable == range->inheritable) 683 { 684 lastrange->end = MAX(range->end, lastrange->end); | 702 } 703 704 /* Combine overlapping or adjacent ranges with the 705 same inheritability. */ 706 if (lastrange->inheritable == range->inheritable) 707 { 708 lastrange->end = MAX(range->end, lastrange->end); |
685 svn_sort__array_delete(rangelist, i, 1); | 709 SVN_ERR(svn_sort__array_delete2(rangelist, i, 1)); |
686 i--; 687 } 688 } 689 lastrange = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *); 690 } 691 692 return SVN_NO_ERROR; 693} --- 93 unchanged lines hidden (view full) --- 787 /* Always return SVN_ERR_MERGEINFO_PARSE_ERROR as the topmost error. */ 788 if (err && err->apr_err != SVN_ERR_MERGEINFO_PARSE_ERROR) 789 err = svn_error_createf(SVN_ERR_MERGEINFO_PARSE_ERROR, err, 790 _("Could not parse mergeinfo string '%s'"), 791 input); 792 return err; 793} 794 | 710 i--; 711 } 712 } 713 lastrange = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *); 714 } 715 716 return SVN_NO_ERROR; 717} --- 93 unchanged lines hidden (view full) --- 811 /* Always return SVN_ERR_MERGEINFO_PARSE_ERROR as the topmost error. */ 812 if (err && err->apr_err != SVN_ERR_MERGEINFO_PARSE_ERROR) 813 err = svn_error_createf(SVN_ERR_MERGEINFO_PARSE_ERROR, err, 814 _("Could not parse mergeinfo string '%s'"), 815 input); 816 return err; 817} 818 |
795/* Cleanup after svn_rangelist_merge2 when it modifies the ending range of 796 a single rangelist element in-place. | 819static const char * 820rangelist_to_string_debug(const svn_rangelist_t *rl, 821 apr_pool_t *pool) 822{ 823 svn_string_t *rls; 824 svn_error_t *err; |
797 | 825 |
798 If *RANGE_INDEX is not a valid element in RANGELIST do nothing. Otherwise 799 ensure that RANGELIST[*RANGE_INDEX]->END does not adjoin or overlap any 800 subsequent ranges in RANGELIST. | 826 err = svn_rangelist_to_string(&rls, rl, pool); 827 if (err) 828 { 829 char *s = apr_psprintf(pool, _("<bad rangelist [%d ranges]: %s>"), 830 rl->nelts, err->message); 831 svn_error_clear(err); 832 return s; 833 } 834 return rls->data; 835} |
801 | 836 |
802 If overlap is found, then remove, modify, and/or add elements to RANGELIST 803 as per the invariants for rangelists documented in svn_mergeinfo.h. If 804 RANGELIST[*RANGE_INDEX]->END adjoins a subsequent element then combine the 805 elements if their inheritability permits -- The inheritance of intersecting 806 and adjoining ranges is handled as per svn_mergeinfo_merge2. Upon return 807 set *RANGE_INDEX to the index of the youngest element modified, added, or 808 adjoined to RANGELIST[*RANGE_INDEX]. | 837static svn_boolean_t 838rangelist_is_sorted(const svn_rangelist_t *rangelist) 839{ 840 int i; |
809 | 841 |
810 Note: Adjoining rangelist elements are those where the end rev of the older 811 element is equal to the start rev of the younger element. | 842 for (i = 1; i < rangelist->nelts; i++) 843 { 844 const svn_merge_range_t *lastrange 845 = APR_ARRAY_IDX(rangelist, i-1, svn_merge_range_t *); 846 const svn_merge_range_t *thisrange 847 = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *); |
812 | 848 |
813 Any new elements inserted into RANGELIST are allocated in RESULT_POOL.*/ 814static void 815adjust_remaining_ranges(svn_rangelist_t *rangelist, 816 int *range_index, 817 apr_pool_t *result_pool) | 849 if (svn_sort_compare_ranges(&lastrange, &thisrange) > 0) 850 return FALSE; 851 } 852 return TRUE; 853} 854 855/* Mergeinfo inheritance or absence in a rangelist interval */ 856enum rangelist_interval_kind_t { MI_NONE, MI_NON_INHERITABLE, MI_INHERITABLE }; 857 858/* A rangelist interval: like svn_merge_range_t but an interval can represent 859 * a gap in the rangelist (kind = MI_NONE). */ 860typedef struct rangelist_interval_t |
818{ | 861{ |
819 int i; 820 int starting_index; 821 int elements_to_delete = 0; 822 svn_merge_range_t *modified_range; | 862 svn_revnum_t start, end; 863 enum rangelist_interval_kind_t kind; 864} rangelist_interval_t; |
823 | 865 |
824 if (*range_index >= rangelist->nelts) 825 return; | 866/* Iterator for intervals in a rangelist. */ 867typedef struct rangelist_interval_iterator_t { 868 /* iteration state: */ 869 const svn_rangelist_t *rl; /* input */ 870 int i; /* current interval is this range in RL or the gap before it */ 871 svn_boolean_t in_range; /* current interval is range RL[I], not a gap? */ |
826 | 872 |
827 starting_index = *range_index + 1; 828 modified_range = APR_ARRAY_IDX(rangelist, *range_index, svn_merge_range_t *); | 873 /* current interval: */ 874 rangelist_interval_t interval; 875} rangelist_interval_iterator_t; |
829 | 876 |
830 for (i = *range_index + 1; i < rangelist->nelts; i++) | 877/* Update IT->interval to match the current iteration state of IT. 878 * Return the iterator, or NULL if the iteration has reached its end. 879 */ 880static rangelist_interval_iterator_t * 881rlii_update(rangelist_interval_iterator_t *it) 882{ 883 const svn_merge_range_t *range 884 = (it->i < it->rl->nelts 885 ? APR_ARRAY_IDX(it->rl, it->i, void *) : NULL); 886 887 if (!range) 888 return NULL; 889 890 if (!it->in_range) |
831 { | 891 { |
832 svn_merge_range_t *next_range = APR_ARRAY_IDX(rangelist, i, 833 svn_merge_range_t *); | 892 it->interval.start 893 = (it->i > 0 894 ? APR_ARRAY_IDX(it->rl, it->i - 1, svn_merge_range_t *)->end 895 : 0); 896 it->interval.end = range->start; 897 it->interval.kind = MI_NONE; 898 } 899 else 900 { 901 it->interval.start = range->start; 902 it->interval.end = range->end; 903 it->interval.kind 904 = (range->inheritable ? MI_INHERITABLE : MI_NON_INHERITABLE); 905 } 906 return it; 907} |
834 | 908 |
835 /* If MODIFIED_RANGE doesn't adjoin or overlap the next range in 836 RANGELIST then we are finished. */ 837 if (modified_range->end < next_range->start) 838 break; | 909/* Move to the next interval, which might be a zero-length interval. 910 * Return IT, or return NULL at the end of iteration. */ 911static rangelist_interval_iterator_t * 912rlii_next_any_interval(rangelist_interval_iterator_t *it) 913{ 914 /* Should be called before iteration is finished. */ 915 if (it->i >= it->rl->nelts) 916 return NULL; |
839 | 917 |
840 /* Does MODIFIED_RANGE adjoin NEXT_RANGE? */ 841 if (modified_range->end == next_range->start) 842 { 843 if (modified_range->inheritable == next_range->inheritable) 844 { 845 /* Combine adjoining ranges with the same inheritability. */ 846 modified_range->end = next_range->end; 847 elements_to_delete++; 848 } 849 else 850 { 851 /* Cannot join because inheritance differs. */ 852 (*range_index)++; 853 } 854 break; 855 } | 918 /* If we are in a range, move to the next pre-range gap; 919 * else, move from this pre-range gap into this range. */ 920 if (it->in_range) 921 it->i++; 922 it->in_range = !it->in_range; 923 return it; 924} |
856 | 925 |
857 /* Alright, we know MODIFIED_RANGE overlaps NEXT_RANGE, but how? */ 858 if (modified_range->end > next_range->end) 859 { 860 /* NEXT_RANGE is a proper subset of MODIFIED_RANGE and the two 861 don't share the same end range. */ 862 if (modified_range->inheritable 863 || (modified_range->inheritable == next_range->inheritable)) 864 { 865 /* MODIFIED_RANGE absorbs NEXT_RANGE. */ 866 elements_to_delete++; 867 } 868 else 869 { 870 /* NEXT_RANGE is a proper subset MODIFIED_RANGE but 871 MODIFIED_RANGE is non-inheritable and NEXT_RANGE is 872 inheritable. This means MODIFIED_RANGE is truncated, 873 NEXT_RANGE remains, and the portion of MODIFIED_RANGE 874 younger than NEXT_RANGE is added as a separate range: 875 ______________________________________________ 876 | | 877 M MODIFIED_RANGE N 878 | (!inheritable) | 879 |______________________________________________| 880 | | 881 O NEXT_RANGE P 882 | (inheritable)| 883 |______________| 884 | 885 V 886 _______________________________________________ 887 | | | | 888 M MODIFIED_RANGE O NEXT_RANGE P NEW_RANGE N 889 | (!inheritable) | (inheritable)| (!inheritable)| 890 |________________|______________|_______________| 891 */ 892 svn_merge_range_t *new_modified_range = 893 apr_palloc(result_pool, sizeof(*new_modified_range)); 894 new_modified_range->start = next_range->end; 895 new_modified_range->end = modified_range->end; 896 new_modified_range->inheritable = FALSE; 897 modified_range->end = next_range->start; 898 (*range_index)+=2; 899 svn_sort__array_insert(rangelist, &new_modified_range, 900 *range_index); 901 /* Recurse with the new range. */ 902 adjust_remaining_ranges(rangelist, range_index, result_pool); 903 break; 904 } 905 } 906 else if (modified_range->end == next_range->end) 907 { 908 /* NEXT_RANGE is a proper subset MODIFIED_RANGE and share 909 the same end range. */ 910 if (modified_range->inheritable 911 || (modified_range->inheritable == next_range->inheritable)) 912 { 913 /* MODIFIED_RANGE absorbs NEXT_RANGE. */ 914 elements_to_delete++; 915 } 916 else 917 { 918 /* The intersection between MODIFIED_RANGE and NEXT_RANGE is 919 absorbed by the latter. */ 920 modified_range->end = next_range->start; 921 (*range_index)++; 922 } 923 break; 924 } 925 else 926 { 927 /* NEXT_RANGE and MODIFIED_RANGE intersect but NEXT_RANGE is not 928 a proper subset of MODIFIED_RANGE, nor do the two share the 929 same end revision, i.e. they overlap. */ 930 if (modified_range->inheritable == next_range->inheritable) 931 { 932 /* Combine overlapping ranges with the same inheritability. */ 933 modified_range->end = next_range->end; 934 elements_to_delete++; 935 } 936 else if (modified_range->inheritable) 937 { 938 /* MODIFIED_RANGE absorbs the portion of NEXT_RANGE it overlaps 939 and NEXT_RANGE is truncated. */ 940 next_range->start = modified_range->end; 941 (*range_index)++; 942 } 943 else 944 { 945 /* NEXT_RANGE absorbs the portion of MODIFIED_RANGE it overlaps 946 and MODIFIED_RANGE is truncated. */ 947 modified_range->end = next_range->start; 948 (*range_index)++; 949 } 950 break; 951 } | 926/* Return an iterator pointing at the first non-zero-length interval in RL, 927 * or NULL if there are none. */ 928static rangelist_interval_iterator_t * 929rlii_first(const svn_rangelist_t *rl, 930 apr_pool_t *pool) 931{ 932 rangelist_interval_iterator_t *it = apr_palloc(pool, sizeof(*it)); 933 934 it->rl = rl; 935 it->i = 0; 936 it->in_range = FALSE; 937 938 /* Update, and skip empty intervals */ 939 while ((it = rlii_update(it)) && it->interval.start == it->interval.end) 940 { 941 it = rlii_next_any_interval(it); |
952 } | 942 } |
943 return it; 944} |
|
953 | 945 |
954 if (elements_to_delete) 955 svn_sort__array_delete(rangelist, starting_index, elements_to_delete); | 946/* Move to the next non-empty interval. 947 * Intervals will be generated in this sequence: 948 * (0, MI_NONE, RL[0]->start), // i=0, !in_range 949 * (RL[0]->start, MI_* RL[0]->end), // i=0, in_range 950 * (RL[0]->end, MI_NONE, RL[1]->start), 951 * (RL[1]->start, MI_* RL[1]->end), 952 * ... 953 * (RL[n-2]->end, MI_NONE, RL[n-1]->start), 954 * (RL[n-1]->start, MI_* RL[n-1]->end), 955 * but excluding empty intervals. 956 * Return IT, or return NULL at the end of iteration. */ 957static rangelist_interval_iterator_t * 958rlii_next(rangelist_interval_iterator_t *it) 959{ 960 it = rlii_next_any_interval(it); 961 962 /* Update, and skip empty intervals */ 963 while ((it = rlii_update(it)) && it->interval.start == it->interval.end) 964 { 965 it = rlii_next_any_interval(it); 966 } 967 return it; |
956} 957 | 968} 969 |
970/* Rangelist builder. Accumulates consecutive intervals, combining them 971 * when possible. */ 972typedef struct rangelist_builder_t { 973 svn_rangelist_t *rl; /* rangelist to build */ 974 rangelist_interval_t accu_interval; /* current interval accumulator */ 975 apr_pool_t *pool; /* from which to allocate ranges */ 976} rangelist_builder_t; 977 978/* Return an initialized rangelist builder. */ 979static rangelist_builder_t * 980rl_builder_new(svn_rangelist_t *rl, 981 apr_pool_t *pool) 982{ 983 rangelist_builder_t *b = apr_pcalloc(pool, sizeof(*b)); 984 985 b->rl = rl; 986 /* b->accu_interval = {0, 0, RL_NONE} */ 987 b->pool = pool; 988 return b; 989} 990 991/* Flush the last accumulated interval in the rangelist builder B. */ 992static void 993rl_builder_flush(rangelist_builder_t *b) 994{ 995 if (b->accu_interval.kind > MI_NONE) 996 { 997 svn_merge_range_t *mrange = apr_pcalloc(b->pool, sizeof(*mrange)); 998 mrange->start = b->accu_interval.start; 999 mrange->end = b->accu_interval.end; 1000 mrange->inheritable = (b->accu_interval.kind == MI_INHERITABLE); 1001 APR_ARRAY_PUSH(b->rl, svn_merge_range_t *) = mrange; 1002 } 1003} 1004 1005/* Add a new INTERVAL to the rangelist builder B. */ 1006static void 1007rl_builder_add_interval(rangelist_builder_t *b, 1008 const rangelist_interval_t *interval) 1009{ 1010 SVN_ERR_ASSERT_NO_RETURN(interval->start < interval->end); 1011 SVN_ERR_ASSERT_NO_RETURN(interval->start == b->accu_interval.end); 1012 1013 /* Extend the accumulating interval, or end it and start another? */ 1014 if (interval->kind == b->accu_interval.kind) 1015 { 1016 b->accu_interval.end = interval->end; 1017 } 1018 else 1019 { 1020 /* Push the accumulated interval onto the building rangelist. */ 1021 rl_builder_flush(b); 1022 /* Start accumulating a new interval */ 1023 b->accu_interval = *interval; 1024 } 1025} 1026 1027/* Set RL_OUT to the union (merge) of RL1 and RL2. 1028 * On entry, RL_OUT must be an empty rangelist. 1029 * 1030 * Each range added to RL_OUT will be either shallow-copied from RL1 or 1031 * allocated from RESULT_POOL. 1032 */ 1033static svn_error_t * 1034rangelist_merge(svn_rangelist_t *rl_out, 1035 const svn_rangelist_t *rl1, 1036 const svn_rangelist_t *rl2, 1037 apr_pool_t *result_pool, 1038 apr_pool_t *scratch_pool) 1039{ 1040 rangelist_interval_iterator_t *it[2]; 1041 rangelist_builder_t *rl_builder = rl_builder_new(rl_out, result_pool); 1042 svn_revnum_t r_last = 0; 1043 1044 /*SVN_ERR_ASSERT(svn_rangelist__is_canonical(rl1));*/ 1045 /*SVN_ERR_ASSERT(svn_rangelist__is_canonical(rl2));*/ 1046 SVN_ERR_ASSERT(rangelist_is_sorted(rl1)); 1047 SVN_ERR_ASSERT(rangelist_is_sorted(rl2)); 1048 SVN_ERR_ASSERT(rl_out->nelts == 0); 1049 1050 /* Initialize the input iterators and the output generator */ 1051 it[0] = rlii_first(rl1, scratch_pool); 1052 it[1] = rlii_first(rl2, scratch_pool); 1053 1054 /* Keep choosing the next input revision (whether a start or end of a range) 1055 * at which to consider making an output transition. */ 1056 while (it[0] || it[1]) 1057 { 1058 svn_revnum_t r_next = !it[1] ? it[0]->interval.end 1059 : !it[0] ? it[1]->interval.end 1060 : MIN(it[0]->interval.end, it[1]->interval.end); 1061 rangelist_interval_t interval; 1062 1063 interval.start = r_last; 1064 interval.end = r_next; 1065 interval.kind = !it[1] ? it[0]->interval.kind 1066 : !it[0] ? it[1]->interval.kind 1067 : MAX(it[0]->interval.kind, it[1]->interval.kind); 1068 1069 /* Accumulate */ 1070 SVN_ERR_ASSERT(interval.start < interval.end); 1071 rl_builder_add_interval(rl_builder, &interval); 1072 1073 /* if we have used up either or both input intervals, increment them */ 1074 if (it[0] && it[0]->interval.end <= r_next) 1075 it[0] = rlii_next(it[0]); 1076 if (it[1] && it[1]->interval.end <= r_next) 1077 it[1] = rlii_next(it[1]); 1078 1079 r_last = interval.end; 1080 } 1081 rl_builder_flush(rl_builder); 1082 return SVN_NO_ERROR; 1083} 1084 |
|
958svn_error_t * 959svn_rangelist_merge2(svn_rangelist_t *rangelist, | 1085svn_error_t * 1086svn_rangelist_merge2(svn_rangelist_t *rangelist, |
960 const svn_rangelist_t *changes, | 1087 const svn_rangelist_t *chg, |
961 apr_pool_t *result_pool, 962 apr_pool_t *scratch_pool) 963{ | 1088 apr_pool_t *result_pool, 1089 apr_pool_t *scratch_pool) 1090{ |
964 int i = 0; 965 int j = 0; | 1091 svn_error_t *err; 1092 svn_rangelist_t *rangelist_orig; |
966 | 1093 |
967 /* We may modify CHANGES, so make a copy in SCRATCH_POOL. */ 968 changes = svn_rangelist_dup(changes, scratch_pool); | 1094#ifdef SVN_DEBUG 1095 SVN_ERR_ASSERT(rangelist_is_sorted(rangelist)); 1096 SVN_ERR_ASSERT(rangelist_is_sorted(chg)); 1097#endif |
969 | 1098 |
970 while (i < rangelist->nelts && j < changes->nelts) 971 { 972 svn_merge_range_t *range = 973 APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *); 974 svn_merge_range_t *change = 975 APR_ARRAY_IDX(changes, j, svn_merge_range_t *); 976 int res = svn_sort_compare_ranges(&range, &change); | 1099 /* Move the original rangelist aside. A shallow copy suffices, 1100 * as rangelist_merge() won't modify its inputs. */ 1101 rangelist_orig = apr_array_copy(scratch_pool, rangelist); 1102 apr_array_clear(rangelist); 1103 err = svn_error_trace(rangelist_merge(rangelist, rangelist_orig, chg, 1104 result_pool, scratch_pool)); |
977 | 1105 |
978 if (res == 0) 979 { 980 /* Only when merging two non-inheritable ranges is the result also 981 non-inheritable. In all other cases ensure an inheritable 982 result. */ 983 if (range->inheritable || change->inheritable) 984 range->inheritable = TRUE; 985 i++; 986 j++; 987 } 988 else if (res < 0) /* CHANGE is younger than RANGE */ 989 { 990 if (range->end < change->start) 991 { 992 /* RANGE is older than CHANGE and the two do not 993 adjoin or overlap */ 994 i++; 995 } 996 else if (range->end == change->start) 997 { 998 /* RANGE and CHANGE adjoin */ 999 if (range->inheritable == change->inheritable) 1000 { 1001 /* RANGE and CHANGE have the same inheritability so 1002 RANGE expands to absord CHANGE. */ 1003 range->end = change->end; 1004 adjust_remaining_ranges(rangelist, &i, result_pool); 1005 j++; 1006 } 1007 else 1008 { 1009 /* RANGE and CHANGE adjoin, but have different 1010 inheritability. Since RANGE is older, just 1011 move on to the next RANGE. */ 1012 i++; 1013 } 1014 } 1015 else 1016 { 1017 /* RANGE and CHANGE overlap, but how? */ 1018 if ((range->inheritable == change->inheritable) 1019 || range->inheritable) 1020 { 1021 /* If CHANGE is a proper subset of RANGE, it absorbs RANGE 1022 with no adjustment otherwise only the intersection is 1023 absorbed and CHANGE is truncated. */ 1024 if (range->end >= change->end) 1025 j++; 1026 else 1027 change->start = range->end; 1028 } 1029 else 1030 { 1031 /* RANGE is non-inheritable and CHANGE is inheritable. */ 1032 if (range->start < change->start) 1033 { 1034 /* CHANGE absorbs intersection with RANGE and RANGE 1035 is truncated. */ 1036 svn_merge_range_t *range_copy = 1037 svn_merge_range_dup(range, result_pool); 1038 range_copy->end = change->start; 1039 range->start = change->start; 1040 svn_sort__array_insert(rangelist, &range_copy, i++); 1041 } 1042 else 1043 { 1044 /* CHANGE and RANGE share the same start rev, but 1045 RANGE is considered older because its end rev 1046 is older. */ 1047 range->inheritable = TRUE; 1048 change->start = range->end; 1049 } 1050 } 1051 } 1052 } 1053 else /* res > 0, CHANGE is older than RANGE */ 1054 { 1055 if (change->end < range->start) 1056 { 1057 /* CHANGE is older than RANGE and the two do not 1058 adjoin or overlap, so insert a copy of CHANGE 1059 into RANGELIST. */ 1060 svn_merge_range_t *change_copy = 1061 svn_merge_range_dup(change, result_pool); 1062 svn_sort__array_insert(rangelist, &change_copy, i++); 1063 j++; 1064 } 1065 else if (change->end == range->start) 1066 { 1067 /* RANGE and CHANGE adjoin */ 1068 if (range->inheritable == change->inheritable) 1069 { 1070 /* RANGE and CHANGE have the same inheritability so we 1071 can simply combine the two in place. */ 1072 range->start = change->start; 1073 j++; 1074 } 1075 else 1076 { 1077 /* RANGE and CHANGE have different inheritability so insert 1078 a copy of CHANGE into RANGELIST. */ 1079 svn_merge_range_t *change_copy = 1080 svn_merge_range_dup(change, result_pool); 1081 svn_sort__array_insert(rangelist, &change_copy, i); 1082 j++; 1083 } 1084 } 1085 else 1086 { 1087 /* RANGE and CHANGE overlap. */ 1088 if (range->inheritable == change->inheritable) 1089 { 1090 /* RANGE and CHANGE have the same inheritability so we 1091 can simply combine the two in place... */ 1092 range->start = change->start; 1093 if (range->end < change->end) 1094 { 1095 /* ...but if RANGE is expanded ensure that we don't 1096 violate any rangelist invariants. */ 1097 range->end = change->end; 1098 adjust_remaining_ranges(rangelist, &i, result_pool); 1099 } 1100 j++; 1101 } 1102 else if (range->inheritable) 1103 { 1104 if (change->start < range->start) 1105 { 1106 /* RANGE is inheritable so absorbs any part of CHANGE 1107 it overlaps. CHANGE is truncated and the remainder 1108 inserted into RANGELIST. */ 1109 svn_merge_range_t *change_copy = 1110 svn_merge_range_dup(change, result_pool); 1111 change_copy->end = range->start; 1112 change->start = range->start; 1113 svn_sort__array_insert(rangelist, &change_copy, i++); 1114 } 1115 else 1116 { 1117 /* CHANGE and RANGE share the same start rev, but 1118 CHANGE is considered older because CHANGE->END is 1119 older than RANGE->END. */ 1120 j++; 1121 } 1122 } 1123 else 1124 { 1125 /* RANGE is non-inheritable and CHANGE is inheritable. */ 1126 if (change->start < range->start) 1127 { 1128 if (change->end == range->end) 1129 { 1130 /* RANGE is a proper subset of CHANGE and share the 1131 same end revision, so set RANGE equal to CHANGE. */ 1132 range->start = change->start; 1133 range->inheritable = TRUE; 1134 j++; 1135 } 1136 else if (change->end > range->end) 1137 { 1138 /* RANGE is a proper subset of CHANGE and CHANGE has 1139 a younger end revision, so set RANGE equal to its 1140 intersection with CHANGE and truncate CHANGE. */ 1141 range->start = change->start; 1142 range->inheritable = TRUE; 1143 change->start = range->end; 1144 } 1145 else 1146 { 1147 /* CHANGE and RANGE overlap. Set RANGE equal to its 1148 intersection with CHANGE and take the remainder 1149 of RANGE and insert it into RANGELIST. */ 1150 svn_merge_range_t *range_copy = 1151 svn_merge_range_dup(range, result_pool); 1152 range_copy->start = change->end; 1153 range->start = change->start; 1154 range->end = change->end; 1155 range->inheritable = TRUE; 1156 svn_sort__array_insert(rangelist, &range_copy, ++i); 1157 j++; 1158 } 1159 } 1160 else 1161 { 1162 /* CHANGE and RANGE share the same start rev, but 1163 CHANGE is considered older because its end rev 1164 is older. 1165 1166 Insert the intersection of RANGE and CHANGE into 1167 RANGELIST and then set RANGE to the non-intersecting 1168 portion of RANGE. */ 1169 svn_merge_range_t *range_copy = 1170 svn_merge_range_dup(range, result_pool); 1171 range_copy->end = change->end; 1172 range_copy->inheritable = TRUE; 1173 range->start = change->end; 1174 svn_sort__array_insert(rangelist, &range_copy, i++); 1175 j++; 1176 } 1177 } 1178 } 1179 } | 1106#ifdef SVN_DEBUG 1107 if (err) 1108 { 1109 err = svn_error_createf(SVN_ERR_ASSERTION_FAIL, err, 1110 "svn_rangelist_merge2( %s / %s ): internal error", 1111 rangelist_to_string_debug(rangelist_orig, scratch_pool), 1112 rangelist_to_string_debug(chg, scratch_pool)); |
1180 } | 1113 } |
1181 1182 /* Copy any remaining elements in CHANGES into RANGELIST. */ 1183 for (; j < (changes)->nelts; j++) | 1114 else if (! svn_rangelist__is_canonical(rangelist) 1115 && svn_rangelist__is_canonical(rangelist_orig) 1116 && svn_rangelist__is_canonical(chg)) |
1184 { | 1117 { |
1185 svn_merge_range_t *change = 1186 APR_ARRAY_IDX(changes, j, svn_merge_range_t *); 1187 svn_merge_range_t *change_copy = svn_merge_range_dup(change, 1188 result_pool); 1189 svn_sort__array_insert(rangelist, &change_copy, rangelist->nelts); | 1118 err = svn_error_createf(SVN_ERR_ASSERTION_FAIL, NULL, 1119 "svn_rangelist_merge2( %s / %s ): canonical inputs, " 1120 "non-canonical result ( %s )", 1121 rangelist_to_string_debug(rangelist_orig, scratch_pool), 1122 rangelist_to_string_debug(chg, scratch_pool), 1123 rangelist_to_string_debug(rangelist, scratch_pool)); |
1190 } | 1124 } |
1125#endif |
|
1191 | 1126 |
1192 return SVN_NO_ERROR; | 1127 return err; |
1193} 1194 | 1128} 1129 |
1195/* Return TRUE iff the forward revision ranges FIRST and SECOND overlap and 1196 * (if CONSIDER_INHERITANCE is TRUE) have the same inheritability. */ 1197static svn_boolean_t 1198range_intersect(const svn_merge_range_t *first, const svn_merge_range_t *second, | 1130/* Set *RESULT to TRUE iff the forward revision ranges FIRST and SECOND overlap 1131 * and (if CONSIDER_INHERITANCE is TRUE) have the same inheritability. */ 1132static svn_error_t * 1133range_intersect(svn_boolean_t *result, 1134 const svn_merge_range_t *first, const svn_merge_range_t *second, |
1199 svn_boolean_t consider_inheritance) 1200{ | 1135 svn_boolean_t consider_inheritance) 1136{ |
1201 SVN_ERR_ASSERT_NO_RETURN(IS_VALID_FORWARD_RANGE(first)); 1202 SVN_ERR_ASSERT_NO_RETURN(IS_VALID_FORWARD_RANGE(second)); | 1137 SVN_ERR_ASSERT(IS_VALID_FORWARD_RANGE(first)); 1138 SVN_ERR_ASSERT(IS_VALID_FORWARD_RANGE(second)); |
1203 | 1139 |
1204 return (first->start + 1 <= second->end) 1205 && (second->start + 1 <= first->end) 1206 && (!consider_inheritance 1207 || (!(first->inheritable) == !(second->inheritable))); | 1140 *result = (first->start + 1 <= second->end) 1141 && (second->start + 1 <= first->end) 1142 && (!consider_inheritance 1143 || (!(first->inheritable) == !(second->inheritable))); 1144 return SVN_NO_ERROR; |
1208} 1209 | 1145} 1146 |
1210/* Return TRUE iff the forward revision range FIRST wholly contains the | 1147/* Set *RESULT to TRUE iff the forward revision range FIRST wholly contains the |
1211 * forward revision range SECOND and (if CONSIDER_INHERITANCE is TRUE) has 1212 * the same inheritability. */ | 1148 * forward revision range SECOND and (if CONSIDER_INHERITANCE is TRUE) has 1149 * the same inheritability. */ |
1213static svn_boolean_t 1214range_contains(const svn_merge_range_t *first, const svn_merge_range_t *second, | 1150static svn_error_t * 1151range_contains(svn_boolean_t *result, 1152 const svn_merge_range_t *first, const svn_merge_range_t *second, |
1215 svn_boolean_t consider_inheritance) 1216{ | 1153 svn_boolean_t consider_inheritance) 1154{ |
1217 SVN_ERR_ASSERT_NO_RETURN(IS_VALID_FORWARD_RANGE(first)); 1218 SVN_ERR_ASSERT_NO_RETURN(IS_VALID_FORWARD_RANGE(second)); | 1155 SVN_ERR_ASSERT(IS_VALID_FORWARD_RANGE(first)); 1156 SVN_ERR_ASSERT(IS_VALID_FORWARD_RANGE(second)); |
1219 | 1157 |
1220 return (first->start <= second->start) && (second->end <= first->end) 1221 && (!consider_inheritance 1222 || (!(first->inheritable) == !(second->inheritable))); | 1158 *result = (first->start <= second->start) && (second->end <= first->end) 1159 && (!consider_inheritance 1160 || (!(first->inheritable) == !(second->inheritable))); 1161 return SVN_NO_ERROR; |
1223} 1224 1225/* Swap start and end fields of RANGE. */ 1226static void 1227range_swap_endpoints(svn_merge_range_t *range) 1228{ 1229 svn_revnum_t swap = range->start; 1230 range->start = range->end; --- 102 unchanged lines hidden (view full) --- 1333 1334 i1 = 0; 1335 i2 = 0; 1336 lasti2 = -1; /* Initialized to a value that "i2" will never be. */ 1337 1338 while (i1 < rangelist1->nelts && i2 < rangelist2->nelts) 1339 { 1340 svn_merge_range_t *elt1, *elt2; | 1162} 1163 1164/* Swap start and end fields of RANGE. */ 1165static void 1166range_swap_endpoints(svn_merge_range_t *range) 1167{ 1168 svn_revnum_t swap = range->start; 1169 range->start = range->end; --- 102 unchanged lines hidden (view full) --- 1272 1273 i1 = 0; 1274 i2 = 0; 1275 lasti2 = -1; /* Initialized to a value that "i2" will never be. */ 1276 1277 while (i1 < rangelist1->nelts && i2 < rangelist2->nelts) 1278 { 1279 svn_merge_range_t *elt1, *elt2; |
1280 svn_boolean_t elt1_contains_elt2, elt1_intersects_elt2; |
|
1341 1342 elt1 = APR_ARRAY_IDX(rangelist1, i1, svn_merge_range_t *); 1343 1344 /* Instead of making a copy of the entire array of rangelist2 1345 elements, we just keep a copy of the current rangelist2 element 1346 that needs to be used, and modify our copy if necessary. */ 1347 if (i2 != lasti2) 1348 { 1349 working_elt2 = 1350 *(APR_ARRAY_IDX(rangelist2, i2, svn_merge_range_t *)); 1351 lasti2 = i2; 1352 } 1353 1354 elt2 = &working_elt2; 1355 | 1281 1282 elt1 = APR_ARRAY_IDX(rangelist1, i1, svn_merge_range_t *); 1283 1284 /* Instead of making a copy of the entire array of rangelist2 1285 elements, we just keep a copy of the current rangelist2 element 1286 that needs to be used, and modify our copy if necessary. */ 1287 if (i2 != lasti2) 1288 { 1289 working_elt2 = 1290 *(APR_ARRAY_IDX(rangelist2, i2, svn_merge_range_t *)); 1291 lasti2 = i2; 1292 } 1293 1294 elt2 = &working_elt2; 1295 |
1296 SVN_ERR(range_contains(&elt1_contains_elt2, 1297 elt1, elt2, consider_inheritance)); 1298 SVN_ERR(range_intersect(&elt1_intersects_elt2, 1299 elt1, elt2, consider_inheritance)); |
|
1356 /* If the rangelist2 range is contained completely in the 1357 rangelist1, we increment the rangelist2. 1358 If the ranges intersect, and match exactly, we increment both 1359 rangelist1 and rangelist2. 1360 Otherwise, we have to generate a range for the left part of 1361 the removal of rangelist1 from rangelist2, and possibly change 1362 the rangelist2 to the remaining portion of the right part of 1363 the removal, to test against. */ | 1300 /* If the rangelist2 range is contained completely in the 1301 rangelist1, we increment the rangelist2. 1302 If the ranges intersect, and match exactly, we increment both 1303 rangelist1 and rangelist2. 1304 Otherwise, we have to generate a range for the left part of 1305 the removal of rangelist1 from rangelist2, and possibly change 1306 the rangelist2 to the remaining portion of the right part of 1307 the removal, to test against. */ |
1364 if (range_contains(elt1, elt2, consider_inheritance)) | 1308 if (elt1_contains_elt2) |
1365 { 1366 if (!do_remove) 1367 { 1368 svn_merge_range_t tmp_range; 1369 tmp_range.start = elt2->start; 1370 tmp_range.end = elt2->end; 1371 /* The intersection of two ranges is non-inheritable only 1372 if both ranges are non-inheritable. */ --- 4 unchanged lines hidden (view full) --- 1377 pool)); 1378 } 1379 1380 i2++; 1381 1382 if (elt2->start == elt1->start && elt2->end == elt1->end) 1383 i1++; 1384 } | 1309 { 1310 if (!do_remove) 1311 { 1312 svn_merge_range_t tmp_range; 1313 tmp_range.start = elt2->start; 1314 tmp_range.end = elt2->end; 1315 /* The intersection of two ranges is non-inheritable only 1316 if both ranges are non-inheritable. */ --- 4 unchanged lines hidden (view full) --- 1321 pool)); 1322 } 1323 1324 i2++; 1325 1326 if (elt2->start == elt1->start && elt2->end == elt1->end) 1327 i1++; 1328 } |
1385 else if (range_intersect(elt1, elt2, consider_inheritance)) | 1329 else if (elt1_intersects_elt2) |
1386 { 1387 if (elt2->start < elt1->start) 1388 { 1389 /* The rangelist2 range starts before the rangelist1 range. */ 1390 svn_merge_range_t tmp_range; 1391 if (do_remove) 1392 { 1393 /* Retain the range that falls before the rangelist1 --- 526 unchanged lines hidden (view full) --- 1920 apr_pool_t *pool) 1921{ 1922 svn_stringbuf_t *buf = svn_stringbuf_create_empty(pool); 1923 1924 if (rangelist->nelts > 0) 1925 { 1926 int i; 1927 svn_merge_range_t *range; | 1330 { 1331 if (elt2->start < elt1->start) 1332 { 1333 /* The rangelist2 range starts before the rangelist1 range. */ 1334 svn_merge_range_t tmp_range; 1335 if (do_remove) 1336 { 1337 /* Retain the range that falls before the rangelist1 --- 526 unchanged lines hidden (view full) --- 1864 apr_pool_t *pool) 1865{ 1866 svn_stringbuf_t *buf = svn_stringbuf_create_empty(pool); 1867 1868 if (rangelist->nelts > 0) 1869 { 1870 int i; 1871 svn_merge_range_t *range; |
1872 char *s; |
|
1928 1929 /* Handle the elements that need commas at the end. */ 1930 for (i = 0; i < rangelist->nelts - 1; i++) 1931 { 1932 range = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *); | 1873 1874 /* Handle the elements that need commas at the end. */ 1875 for (i = 0; i < rangelist->nelts - 1; i++) 1876 { 1877 range = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *); |
1933 svn_stringbuf_appendcstr(buf, range_to_string(range, pool)); | 1878 SVN_ERR(range_to_string(&s, range, pool)); 1879 svn_stringbuf_appendcstr(buf, s); |
1934 svn_stringbuf_appendcstr(buf, ","); 1935 } 1936 1937 /* Now handle the last element, which needs no comma. */ 1938 range = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *); | 1880 svn_stringbuf_appendcstr(buf, ","); 1881 } 1882 1883 /* Now handle the last element, which needs no comma. */ 1884 range = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *); |
1939 svn_stringbuf_appendcstr(buf, range_to_string(range, pool)); | 1885 SVN_ERR(range_to_string(&s, range, pool)); 1886 svn_stringbuf_appendcstr(buf, s); |
1940 } 1941 1942 *output = svn_stringbuf__morph_into_string(buf); 1943 1944 return SVN_NO_ERROR; 1945} 1946 1947/* Converts a mergeinfo INPUT to an unparsed mergeinfo in OUTPUT. If PREFIX --- 353 unchanged lines hidden (view full) --- 2301svn_rangelist_dup(const svn_rangelist_t *rangelist, apr_pool_t *pool) 2302{ 2303 return ptr_array_dup(rangelist, sizeof(svn_merge_range_t), pool); 2304} 2305 2306svn_merge_range_t * 2307svn_merge_range_dup(const svn_merge_range_t *range, apr_pool_t *pool) 2308{ | 1887 } 1888 1889 *output = svn_stringbuf__morph_into_string(buf); 1890 1891 return SVN_NO_ERROR; 1892} 1893 1894/* Converts a mergeinfo INPUT to an unparsed mergeinfo in OUTPUT. If PREFIX --- 353 unchanged lines hidden (view full) --- 2248svn_rangelist_dup(const svn_rangelist_t *rangelist, apr_pool_t *pool) 2249{ 2250 return ptr_array_dup(rangelist, sizeof(svn_merge_range_t), pool); 2251} 2252 2253svn_merge_range_t * 2254svn_merge_range_dup(const svn_merge_range_t *range, apr_pool_t *pool) 2255{ |
2309 svn_merge_range_t *new_range = apr_palloc(pool, sizeof(*new_range)); 2310 memcpy(new_range, range, sizeof(*new_range)); | 2256 svn_merge_range_t *new_range = apr_pmemdup(pool, range, sizeof(*new_range)); |
2311 return new_range; 2312} 2313 2314svn_boolean_t 2315svn_merge_range_contains_rev(const svn_merge_range_t *range, svn_revnum_t rev) 2316{ 2317 assert(SVN_IS_VALID_REVNUM(range->start)); 2318 assert(SVN_IS_VALID_REVNUM(range->end)); --- 36 unchanged lines hidden (view full) --- 2355 svn_stringbuf_appendcstr(output_buf, path1); 2356 svn_stringbuf_appendcstr(output_buf, "\n"); 2357 SVN_ERR(mergeinfo_to_stringbuf(&mergeinfo_output_buf, mergeinfo, 2358 val_prefix ? val_prefix : "", pool)); 2359 svn_stringbuf_appendstr(output_buf, mergeinfo_output_buf); 2360 svn_stringbuf_appendcstr(output_buf, "\n"); 2361 } 2362 } | 2257 return new_range; 2258} 2259 2260svn_boolean_t 2261svn_merge_range_contains_rev(const svn_merge_range_t *range, svn_revnum_t rev) 2262{ 2263 assert(SVN_IS_VALID_REVNUM(range->start)); 2264 assert(SVN_IS_VALID_REVNUM(range->end)); --- 36 unchanged lines hidden (view full) --- 2301 svn_stringbuf_appendcstr(output_buf, path1); 2302 svn_stringbuf_appendcstr(output_buf, "\n"); 2303 SVN_ERR(mergeinfo_to_stringbuf(&mergeinfo_output_buf, mergeinfo, 2304 val_prefix ? val_prefix : "", pool)); 2305 svn_stringbuf_appendstr(output_buf, mergeinfo_output_buf); 2306 svn_stringbuf_appendcstr(output_buf, "\n"); 2307 } 2308 } |
2363#if SVN_DEBUG | 2309#ifdef SVN_DEBUG |
2364 else if (!catalog) 2365 { 2366 output_buf = svn_stringbuf_create(key_prefix ? key_prefix : "", pool); 2367 svn_stringbuf_appendcstr(output_buf, _("NULL mergeinfo catalog\n")); 2368 } 2369 else if (apr_hash_count(catalog) == 0) 2370 { 2371 output_buf = svn_stringbuf_create(key_prefix ? key_prefix : "", pool); --- 319 unchanged lines hidden --- | 2310 else if (!catalog) 2311 { 2312 output_buf = svn_stringbuf_create(key_prefix ? key_prefix : "", pool); 2313 svn_stringbuf_appendcstr(output_buf, _("NULL mergeinfo catalog\n")); 2314 } 2315 else if (apr_hash_count(catalog) == 0) 2316 { 2317 output_buf = svn_stringbuf_create(key_prefix ? key_prefix : "", pool); --- 319 unchanged lines hidden --- |