comparison src/intervals.c @ 50471:dc1f6aa29285

Add many calls to CHECK_TOTAL_LENGTH. (set_intervals_multibyte_1): When becoming multibyte, adjust right and left child sizes to a whole set of characters. If an interval gets zero total-length, delete it. If an interval consists of just its children, delete one of them.
author Richard M. Stallman <rms@gnu.org>
date Sun, 06 Apr 2003 20:32:52 +0000
parents 080b4586492b
children 1b235b3762ff
comparison
equal deleted inserted replaced
50470:c7a0b787faef 50471:dc1f6aa29285
73 73
74 if (BUFFERP (parent)) 74 if (BUFFERP (parent))
75 { 75 {
76 new->total_length = (BUF_Z (XBUFFER (parent)) 76 new->total_length = (BUF_Z (XBUFFER (parent))
77 - BUF_BEG (XBUFFER (parent))); 77 - BUF_BEG (XBUFFER (parent)));
78 CHECK_TOTAL_LENGTH (new);
78 BUF_INTERVALS (XBUFFER (parent)) = new; 79 BUF_INTERVALS (XBUFFER (parent)) = new;
79 new->position = 1; 80 new->position = 1;
80 } 81 }
81 else if (STRINGP (parent)) 82 else if (STRINGP (parent))
82 { 83 {
83 new->total_length = SCHARS (parent); 84 new->total_length = SCHARS (parent);
85 CHECK_TOTAL_LENGTH (new);
84 STRING_SET_INTERVALS (parent, new); 86 STRING_SET_INTERVALS (parent, new);
85 new->position = 0; 87 new->position = 0;
86 } 88 }
87 89
88 SET_INTERVAL_OBJECT (new, parent); 90 SET_INTERVAL_OBJECT (new, parent);
336 if (! NULL_INTERVAL_P (i)) 338 if (! NULL_INTERVAL_P (i))
337 SET_INTERVAL_PARENT (i, interval); 339 SET_INTERVAL_PARENT (i, interval);
338 340
339 /* A's total length is decreased by the length of B and its left child. */ 341 /* A's total length is decreased by the length of B and its left child. */
340 interval->total_length -= B->total_length - LEFT_TOTAL_LENGTH (interval); 342 interval->total_length -= B->total_length - LEFT_TOTAL_LENGTH (interval);
343 CHECK_TOTAL_LENGTH (interval);
341 344
342 /* B must have the same total length of A. */ 345 /* B must have the same total length of A. */
343 B->total_length = old_total; 346 B->total_length = old_total;
347 CHECK_TOTAL_LENGTH (B);
344 348
345 return B; 349 return B;
346 } 350 }
347 351
348 /* Assuming that a right child exists, perform the following operation: 352 /* Assuming that a right child exists, perform the following operation:
382 if (! NULL_INTERVAL_P (i)) 386 if (! NULL_INTERVAL_P (i))
383 SET_INTERVAL_PARENT (i, interval); 387 SET_INTERVAL_PARENT (i, interval);
384 388
385 /* A's total length is decreased by the length of B and its right child. */ 389 /* A's total length is decreased by the length of B and its right child. */
386 interval->total_length -= B->total_length - RIGHT_TOTAL_LENGTH (interval); 390 interval->total_length -= B->total_length - RIGHT_TOTAL_LENGTH (interval);
391 CHECK_TOTAL_LENGTH (interval);
387 392
388 /* B must have the same total length of A. */ 393 /* B must have the same total length of A. */
389 B->total_length = old_total; 394 B->total_length = old_total;
395 CHECK_TOTAL_LENGTH (B);
390 396
391 return B; 397 return B;
392 } 398 }
393 399
394 /* Balance an interval tree with the assumption that the subtrees 400 /* Balance an interval tree with the assumption that the subtrees
403 while (1) 409 while (1)
404 { 410 {
405 old_diff = LEFT_TOTAL_LENGTH (i) - RIGHT_TOTAL_LENGTH (i); 411 old_diff = LEFT_TOTAL_LENGTH (i) - RIGHT_TOTAL_LENGTH (i);
406 if (old_diff > 0) 412 if (old_diff > 0)
407 { 413 {
414 /* Since the left child is longer, there must be one. */
408 new_diff = i->total_length - i->left->total_length 415 new_diff = i->total_length - i->left->total_length
409 + RIGHT_TOTAL_LENGTH (i->left) - LEFT_TOTAL_LENGTH (i->left); 416 + RIGHT_TOTAL_LENGTH (i->left) - LEFT_TOTAL_LENGTH (i->left);
410 if (abs (new_diff) >= old_diff) 417 if (abs (new_diff) >= old_diff)
411 break; 418 break;
412 i = rotate_right (i); 419 i = rotate_right (i);
413 balance_an_interval (i->right); 420 balance_an_interval (i->right);
414 } 421 }
415 else if (old_diff < 0) 422 else if (old_diff < 0)
416 { 423 {
424 /* Since the right child is longer, there must be one. */
417 new_diff = i->total_length - i->right->total_length 425 new_diff = i->total_length - i->right->total_length
418 + LEFT_TOTAL_LENGTH (i->right) - RIGHT_TOTAL_LENGTH (i->right); 426 + LEFT_TOTAL_LENGTH (i->right) - RIGHT_TOTAL_LENGTH (i->right);
419 if (abs (new_diff) >= -old_diff) 427 if (abs (new_diff) >= -old_diff)
420 break; 428 break;
421 i = rotate_left (i); 429 i = rotate_left (i);
512 520
513 if (NULL_RIGHT_CHILD (interval)) 521 if (NULL_RIGHT_CHILD (interval))
514 { 522 {
515 interval->right = new; 523 interval->right = new;
516 new->total_length = new_length; 524 new->total_length = new_length;
525 CHECK_TOTAL_LENGTH (new);
517 } 526 }
518 else 527 else
519 { 528 {
520 /* Insert the new node between INTERVAL and its right child. */ 529 /* Insert the new node between INTERVAL and its right child. */
521 new->right = interval->right; 530 new->right = interval->right;
522 SET_INTERVAL_PARENT (interval->right, new); 531 SET_INTERVAL_PARENT (interval->right, new);
523 interval->right = new; 532 interval->right = new;
524 new->total_length = new_length + new->right->total_length; 533 new->total_length = new_length + new->right->total_length;
534 CHECK_TOTAL_LENGTH (new);
525 balance_an_interval (new); 535 balance_an_interval (new);
526 } 536 }
527 537
528 balance_possible_root_interval (interval); 538 balance_possible_root_interval (interval);
529 539
557 567
558 if (NULL_LEFT_CHILD (interval)) 568 if (NULL_LEFT_CHILD (interval))
559 { 569 {
560 interval->left = new; 570 interval->left = new;
561 new->total_length = new_length; 571 new->total_length = new_length;
572 CHECK_TOTAL_LENGTH (new);
562 } 573 }
563 else 574 else
564 { 575 {
565 /* Insert the new node between INTERVAL and its left child. */ 576 /* Insert the new node between INTERVAL and its left child. */
566 new->left = interval->left; 577 new->left = interval->left;
567 SET_INTERVAL_PARENT (new->left, new); 578 SET_INTERVAL_PARENT (new->left, new);
568 interval->left = new; 579 interval->left = new;
569 new->total_length = new_length + new->left->total_length; 580 new->total_length = new_length + new->left->total_length;
581 CHECK_TOTAL_LENGTH (new);
570 balance_an_interval (new); 582 balance_an_interval (new);
571 } 583 }
572 584
573 balance_possible_root_interval (interval); 585 balance_possible_root_interval (interval);
574 586
826 while (1) 838 while (1)
827 { 839 {
828 if (relative_position <= LEFT_TOTAL_LENGTH (this)) 840 if (relative_position <= LEFT_TOTAL_LENGTH (this))
829 { 841 {
830 this->total_length += length; 842 this->total_length += length;
843 CHECK_TOTAL_LENGTH (this);
831 this = this->left; 844 this = this->left;
832 } 845 }
833 else if (relative_position > (TOTAL_LENGTH (this) 846 else if (relative_position > (TOTAL_LENGTH (this)
834 - RIGHT_TOTAL_LENGTH (this))) 847 - RIGHT_TOTAL_LENGTH (this)))
835 { 848 {
836 relative_position -= (TOTAL_LENGTH (this) 849 relative_position -= (TOTAL_LENGTH (this)
837 - RIGHT_TOTAL_LENGTH (this)); 850 - RIGHT_TOTAL_LENGTH (this));
838 this->total_length += length; 851 this->total_length += length;
852 CHECK_TOTAL_LENGTH (this);
839 this = this->right; 853 this = this->right;
840 } 854 }
841 else 855 else
842 { 856 {
843 /* If we are to use zero-length intervals as buffer pointers, 857 /* If we are to use zero-length intervals as buffer pointers,
844 then this code will have to change. */ 858 then this code will have to change. */
845 this->total_length += length; 859 this->total_length += length;
860 CHECK_TOTAL_LENGTH (this);
846 this->position = LEFT_TOTAL_LENGTH (this) 861 this->position = LEFT_TOTAL_LENGTH (this)
847 + position - relative_position + 1; 862 + position - relative_position + 1;
848 return tree; 863 return tree;
849 } 864 }
850 } 865 }
985 to the left one if it exists. We extend it now and split 1000 to the left one if it exists. We extend it now and split
986 off a part later, if stickiness demands it. */ 1001 off a part later, if stickiness demands it. */
987 for (temp = prev ? prev : i; temp; temp = INTERVAL_PARENT_OR_NULL (temp)) 1002 for (temp = prev ? prev : i; temp; temp = INTERVAL_PARENT_OR_NULL (temp))
988 { 1003 {
989 temp->total_length += length; 1004 temp->total_length += length;
1005 CHECK_TOTAL_LENGTH (temp);
990 temp = balance_possible_root_interval (temp); 1006 temp = balance_possible_root_interval (temp);
991 } 1007 }
992 1008
993 /* If at least one interval has sticky properties, 1009 /* If at least one interval has sticky properties,
994 we check the stickiness property by property. 1010 we check the stickiness property by property.
1041 else 1057 else
1042 { 1058 {
1043 for (temp = i; temp; temp = INTERVAL_PARENT_OR_NULL (temp)) 1059 for (temp = i; temp; temp = INTERVAL_PARENT_OR_NULL (temp))
1044 { 1060 {
1045 temp->total_length += length; 1061 temp->total_length += length;
1062 CHECK_TOTAL_LENGTH (temp);
1046 temp = balance_possible_root_interval (temp); 1063 temp = balance_possible_root_interval (temp);
1047 } 1064 }
1048 } 1065 }
1049 1066
1050 return tree; 1067 return tree;
1245 while (! NULL_INTERVAL_P (this->left)) 1262 while (! NULL_INTERVAL_P (this->left))
1246 { 1263 {
1247 this = this->left; 1264 this = this->left;
1248 this->total_length += migrate_amt; 1265 this->total_length += migrate_amt;
1249 } 1266 }
1267 CHECK_TOTAL_LENGTH (this);
1250 this->left = migrate; 1268 this->left = migrate;
1251 SET_INTERVAL_PARENT (migrate, this); 1269 SET_INTERVAL_PARENT (migrate, this);
1252 1270
1253 return i->right; 1271 return i->right;
1254 } 1272 }
1329 { 1347 {
1330 int subtract = interval_deletion_adjustment (tree->left, 1348 int subtract = interval_deletion_adjustment (tree->left,
1331 relative_position, 1349 relative_position,
1332 amount); 1350 amount);
1333 tree->total_length -= subtract; 1351 tree->total_length -= subtract;
1352 CHECK_TOTAL_LENGTH (tree);
1334 return subtract; 1353 return subtract;
1335 } 1354 }
1336 /* Right branch */ 1355 /* Right branch */
1337 else if (relative_position >= (TOTAL_LENGTH (tree) 1356 else if (relative_position >= (TOTAL_LENGTH (tree)
1338 - RIGHT_TOTAL_LENGTH (tree))) 1357 - RIGHT_TOTAL_LENGTH (tree)))
1343 - RIGHT_TOTAL_LENGTH (tree)); 1362 - RIGHT_TOTAL_LENGTH (tree));
1344 subtract = interval_deletion_adjustment (tree->right, 1363 subtract = interval_deletion_adjustment (tree->right,
1345 relative_position, 1364 relative_position,
1346 amount); 1365 amount);
1347 tree->total_length -= subtract; 1366 tree->total_length -= subtract;
1367 CHECK_TOTAL_LENGTH (tree);
1348 return subtract; 1368 return subtract;
1349 } 1369 }
1350 /* Here -- this node. */ 1370 /* Here -- this node. */
1351 else 1371 else
1352 { 1372 {
1357 1377
1358 if (amount > my_amount) 1378 if (amount > my_amount)
1359 amount = my_amount; 1379 amount = my_amount;
1360 1380
1361 tree->total_length -= amount; 1381 tree->total_length -= amount;
1382 CHECK_TOTAL_LENGTH (tree);
1362 if (LENGTH (tree) == 0) 1383 if (LENGTH (tree) == 0)
1363 delete_interval (tree); 1384 delete_interval (tree);
1364 1385
1365 return amount; 1386 return amount;
1366 } 1387 }
1400 } 1421 }
1401 1422
1402 if (ONLY_INTERVAL_P (tree)) 1423 if (ONLY_INTERVAL_P (tree))
1403 { 1424 {
1404 tree->total_length -= length; 1425 tree->total_length -= length;
1426 CHECK_TOTAL_LENGTH (tree);
1405 return; 1427 return;
1406 } 1428 }
1407 1429
1408 if (start > offset + TOTAL_LENGTH (tree)) 1430 if (start > offset + TOTAL_LENGTH (tree))
1409 start = offset + TOTAL_LENGTH (tree); 1431 start = offset + TOTAL_LENGTH (tree);
1455 register int absorb = LENGTH (i); 1477 register int absorb = LENGTH (i);
1456 register INTERVAL successor; 1478 register INTERVAL successor;
1457 1479
1458 /* Zero out this interval. */ 1480 /* Zero out this interval. */
1459 i->total_length -= absorb; 1481 i->total_length -= absorb;
1482 CHECK_TOTAL_LENGTH (i);
1460 1483
1461 /* Find the succeeding interval. */ 1484 /* Find the succeeding interval. */
1462 if (! NULL_RIGHT_CHILD (i)) /* It's below us. Add absorb 1485 if (! NULL_RIGHT_CHILD (i)) /* It's below us. Add absorb
1463 as we descend. */ 1486 as we descend. */
1464 { 1487 {
1465 successor = i->right; 1488 successor = i->right;
1466 while (! NULL_LEFT_CHILD (successor)) 1489 while (! NULL_LEFT_CHILD (successor))
1467 { 1490 {
1468 successor->total_length += absorb; 1491 successor->total_length += absorb;
1492 CHECK_TOTAL_LENGTH (successor);
1469 successor = successor->left; 1493 successor = successor->left;
1470 } 1494 }
1471 1495
1472 successor->total_length += absorb; 1496 successor->total_length += absorb;
1497 CHECK_TOTAL_LENGTH (successor);
1473 delete_interval (i); 1498 delete_interval (i);
1474 return successor; 1499 return successor;
1475 } 1500 }
1476 1501
1477 successor = i; 1502 successor = i;
1485 return successor; 1510 return successor;
1486 } 1511 }
1487 1512
1488 successor = INTERVAL_PARENT (successor); 1513 successor = INTERVAL_PARENT (successor);
1489 successor->total_length -= absorb; 1514 successor->total_length -= absorb;
1515 CHECK_TOTAL_LENGTH (successor);
1490 } 1516 }
1491 1517
1492 /* This must be the rightmost or last interval and cannot 1518 /* This must be the rightmost or last interval and cannot
1493 be merged right. The caller should have known. */ 1519 be merged right. The caller should have known. */
1494 abort (); 1520 abort ();
1508 register int absorb = LENGTH (i); 1534 register int absorb = LENGTH (i);
1509 register INTERVAL predecessor; 1535 register INTERVAL predecessor;
1510 1536
1511 /* Zero out this interval. */ 1537 /* Zero out this interval. */
1512 i->total_length -= absorb; 1538 i->total_length -= absorb;
1539 CHECK_TOTAL_LENGTH (i);
1513 1540
1514 /* Find the preceding interval. */ 1541 /* Find the preceding interval. */
1515 if (! NULL_LEFT_CHILD (i)) /* It's below us. Go down, 1542 if (! NULL_LEFT_CHILD (i)) /* It's below us. Go down,
1516 adding ABSORB as we go. */ 1543 adding ABSORB as we go. */
1517 { 1544 {
1518 predecessor = i->left; 1545 predecessor = i->left;
1519 while (! NULL_RIGHT_CHILD (predecessor)) 1546 while (! NULL_RIGHT_CHILD (predecessor))
1520 { 1547 {
1521 predecessor->total_length += absorb; 1548 predecessor->total_length += absorb;
1549 CHECK_TOTAL_LENGTH (predecessor);
1522 predecessor = predecessor->right; 1550 predecessor = predecessor->right;
1523 } 1551 }
1524 1552
1525 predecessor->total_length += absorb; 1553 predecessor->total_length += absorb;
1554 CHECK_TOTAL_LENGTH (predecessor);
1526 delete_interval (i); 1555 delete_interval (i);
1527 return predecessor; 1556 return predecessor;
1528 } 1557 }
1529 1558
1530 predecessor = i; 1559 predecessor = i;
1538 return predecessor; 1567 return predecessor;
1539 } 1568 }
1540 1569
1541 predecessor = INTERVAL_PARENT (predecessor); 1570 predecessor = INTERVAL_PARENT (predecessor);
1542 predecessor->total_length -= absorb; 1571 predecessor->total_length -= absorb;
1572 CHECK_TOTAL_LENGTH (predecessor);
1543 } 1573 }
1544 1574
1545 /* This must be the leftmost or first interval and cannot 1575 /* This must be the leftmost or first interval and cannot
1546 be merged left. The caller should have known. */ 1576 be merged left. The caller should have known. */
1547 abort (); 1577 abort ();
2352 2382
2353 new = make_interval (); 2383 new = make_interval ();
2354 new->position = 0; 2384 new->position = 0;
2355 got = (LENGTH (i) - (start - i->position)); 2385 got = (LENGTH (i) - (start - i->position));
2356 new->total_length = length; 2386 new->total_length = length;
2387 CHECK_TOTAL_LENGTH (new);
2357 copy_properties (i, new); 2388 copy_properties (i, new);
2358 2389
2359 t = new; 2390 t = new;
2360 prevlen = got; 2391 prevlen = got;
2361 while (got < length) 2392 while (got < length)
2438 /* Fix the length of this interval. */ 2469 /* Fix the length of this interval. */
2439 if (multi_flag) 2470 if (multi_flag)
2440 i->total_length = end - start; 2471 i->total_length = end - start;
2441 else 2472 else
2442 i->total_length = end_byte - start_byte; 2473 i->total_length = end_byte - start_byte;
2474 CHECK_TOTAL_LENGTH (i);
2475
2476 if (TOTAL_LENGTH (i) == 0)
2477 {
2478 delete_interval (i);
2479 return;
2480 }
2443 2481
2444 /* Recursively fix the length of the subintervals. */ 2482 /* Recursively fix the length of the subintervals. */
2445 if (i->left) 2483 if (i->left)
2446 { 2484 {
2447 int left_end, left_end_byte; 2485 int left_end, left_end_byte;
2448 2486
2449 if (multi_flag) 2487 if (multi_flag)
2450 { 2488 {
2489 int temp;
2451 left_end_byte = start_byte + LEFT_TOTAL_LENGTH (i); 2490 left_end_byte = start_byte + LEFT_TOTAL_LENGTH (i);
2452 left_end = BYTE_TO_CHAR (left_end_byte); 2491 left_end = BYTE_TO_CHAR (left_end_byte);
2492
2493 temp = CHAR_TO_BYTE (left_end);
2494
2495 /* If LEFT_END_BYTE is in the middle of a character,
2496 adjust it and LEFT_END to a char boundary. */
2497 if (left_end_byte > temp)
2498 {
2499 left_end_byte = temp;
2500 }
2501 if (left_end_byte < temp)
2502 {
2503 left_end--;
2504 left_end_byte = CHAR_TO_BYTE (left_end);
2505 }
2453 } 2506 }
2454 else 2507 else
2455 { 2508 {
2456 left_end = start + LEFT_TOTAL_LENGTH (i); 2509 left_end = start + LEFT_TOTAL_LENGTH (i);
2457 left_end_byte = CHAR_TO_BYTE (left_end); 2510 left_end_byte = CHAR_TO_BYTE (left_end);
2464 { 2517 {
2465 int right_start_byte, right_start; 2518 int right_start_byte, right_start;
2466 2519
2467 if (multi_flag) 2520 if (multi_flag)
2468 { 2521 {
2522 int temp;
2523
2469 right_start_byte = end_byte - RIGHT_TOTAL_LENGTH (i); 2524 right_start_byte = end_byte - RIGHT_TOTAL_LENGTH (i);
2470 right_start = BYTE_TO_CHAR (right_start_byte); 2525 right_start = BYTE_TO_CHAR (right_start_byte);
2526
2527 /* If RIGHT_START_BYTE is in the middle of a character,
2528 adjust it and RIGHT_START to a char boundary. */
2529 temp = CHAR_TO_BYTE (right_start);
2530
2531 if (right_start_byte < temp)
2532 {
2533 right_start_byte = temp;
2534 }
2535 if (right_start_byte > temp)
2536 {
2537 right_start++;
2538 right_start_byte = CHAR_TO_BYTE (right_start);
2539 }
2471 } 2540 }
2472 else 2541 else
2473 { 2542 {
2474 right_start = end - RIGHT_TOTAL_LENGTH (i); 2543 right_start = end - RIGHT_TOTAL_LENGTH (i);
2475 right_start_byte = CHAR_TO_BYTE (right_start); 2544 right_start_byte = CHAR_TO_BYTE (right_start);
2477 2546
2478 set_intervals_multibyte_1 (i->right, multi_flag, 2547 set_intervals_multibyte_1 (i->right, multi_flag,
2479 right_start, right_start_byte, 2548 right_start, right_start_byte,
2480 end, end_byte); 2549 end, end_byte);
2481 } 2550 }
2551
2552 /* Rounding to char boundaries can theoretically ake this interval
2553 spurious. If so, delete one child, and copy its property list
2554 to this interval. */
2555 if (LEFT_TOTAL_LENGTH (i) + RIGHT_TOTAL_LENGTH (i) >= TOTAL_LENGTH (i))
2556 {
2557 if ((i)->left)
2558 {
2559 (i)->plist = (i)->left->plist;
2560 (i)->left->total_length = 0;
2561 delete_interval ((i)->left);
2562 }
2563 else
2564 {
2565 (i)->plist = (i)->right->plist;
2566 (i)->right->total_length = 0;
2567 delete_interval ((i)->right);
2568 }
2569 }
2482 } 2570 }
2483 2571
2484 /* Update the intervals of the current buffer 2572 /* Update the intervals of the current buffer
2485 to fit the contents as multibyte (if MULTI_FLAG is 1) 2573 to fit the contents as multibyte (if MULTI_FLAG is 1)
2486 or to fit them as non-multibyte (if MULTI_FLAG is 0). */ 2574 or to fit them as non-multibyte (if MULTI_FLAG is 0). */