1 19 20 package org.netbeans.editor; 21 22 import java.util.List ; 23 import javax.swing.text.Position ; 24 25 33 34 final class MarkVector { 35 36 37 private static final MultiMark[] EMPTY = new MultiMark[0]; 38 39 40 private static final int INITIAL_OFFSET_GAP_SIZE = (Integer.MAX_VALUE >> 1); 41 42 43 private MultiMark[] markArray; 44 45 46 private int gapStart; 47 48 51 private int gapLength; 52 53 54 private int offsetGapStart; 55 56 57 private int offsetGapLength; 58 59 62 private int disposedMarkCount; 63 64 MarkVector() { 65 markArray = EMPTY; 66 offsetGapLength = INITIAL_OFFSET_GAP_SIZE; 67 } 68 69 74 MultiMark createBiasMark(int offset, Position.Bias bias) { 75 return new MultiMark(this, offset, bias); 76 } 77 78 82 MultiMark createMark(int offset) { 83 return new MultiMark(this, offset); 84 } 85 86 88 int getMarkCount() { 89 return markArray.length - gapLength; 90 } 91 92 MultiMark getMark(int index) { 93 return markArray[getRawIndex(index)]; 94 } 95 96 int getMarkOffsetInternal(int index) { 97 return getOffset(getMark(index).rawOffset); 98 } 99 100 105 synchronized MultiMark insert(MultiMark mark) { 106 int flags = mark.flags; 107 if ((flags & MultiMark.VALID) != 0) { throw new IllegalStateException (); 109 } 110 111 int offset = mark.rawOffset; 112 int index = findInsertIndex(offset); 113 if (gapLength == 0) { 114 enlargeGap(1); 115 } 116 if (index != gapStart) { 117 moveGap(index); 118 } 119 120 if (offset > offsetGapStart 121 || (offset == offsetGapStart 122 && ((flags & MultiMark.BACKWARD_BIAS) == 0)) 123 ) { mark.rawOffset += offsetGapLength; 125 } 126 127 markArray[gapStart++] = mark; 128 gapLength--; 129 mark.flags |= MultiMark.VALID; 130 131 return mark; 132 } 133 134 139 synchronized void insertList(List markList) { 140 int lastOffset = Integer.MAX_VALUE; 141 boolean lastBackwardBias = true; 142 int upperOffset = 0; 143 boolean upperBackwardBias = false; 144 int markCount = getMarkCount(); 145 int insertMarkCount = markList.size(); 146 147 if (gapLength < insertMarkCount) { 148 enlargeGap(insertMarkCount); } 150 151 for (int i = 0; i < insertMarkCount; i++ ) { 152 MultiMark mark = (MultiMark)markList.get(i); 153 int flags = mark.flags; 154 if ((flags & MultiMark.VALID) != 0) { throw new IllegalStateException (); 156 } 157 boolean backwardBias = ((flags & MultiMark.BACKWARD_BIAS) != 0); 158 159 int offset = mark.rawOffset; 160 if ((offset < lastOffset) 161 || (offset == lastOffset && backwardBias && !lastBackwardBias) 162 || (offset > upperOffset) 163 || (offset == upperOffset && !backwardBias && upperBackwardBias) 164 ) { 165 int index = findInsertIndex(offset); 167 if (index != gapStart) { 168 moveGap(index); 169 } 170 171 if (index < markCount) { 172 MultiMark m = markArray[getRawIndex(index)]; 173 upperOffset = getOffset(m.rawOffset); 174 upperBackwardBias = ((m.flags & MultiMark.BACKWARD_BIAS) != 0); 175 176 } else { upperOffset = Integer.MAX_VALUE; 178 upperBackwardBias = false; 179 } 180 } 181 182 if (offset > offsetGapStart 183 || (offset == offsetGapStart 184 && ((flags & MultiMark.BACKWARD_BIAS) == 0)) 185 ) { mark.rawOffset += offsetGapLength; 187 } 188 189 markArray[gapStart++] = mark; 190 gapLength--; 191 mark.flags |= MultiMark.VALID; 192 193 lastOffset = offset; 194 lastBackwardBias = backwardBias; 195 markCount++; 196 } 197 } 198 199 synchronized void notifyMarkDisposed() { 200 disposedMarkCount++; 201 202 if (disposedMarkCount > Math.max(5, getMarkCount() / 10)) { 203 removeDisposedMarks(); 204 } 205 } 206 207 synchronized void compact() { 208 if (gapLength > 0) { 209 int newLength = markArray.length - gapLength; 210 MultiMark[] newMarkArray = new MultiMark[newLength]; 211 int gapEnd = gapStart + gapLength; 212 System.arraycopy(markArray, 0, newMarkArray, 0, gapStart); 213 System.arraycopy(markArray, gapEnd, newMarkArray, gapStart, 214 markArray.length - gapEnd); 215 markArray = newMarkArray; 216 gapStart = markArray.length; 217 gapLength = 0; 218 } 219 } 220 221 234 synchronized Undo update(int offset, int length, Undo undo) { 235 if (length < 0) { offset -= length; } 238 239 int offsetGapIndex = findInsertIndex(offset); 241 242 moveOffsetGap(offsetGapIndex, offset); 243 offsetGapStart += length; 244 offsetGapLength -= length; 245 246 if (length >= 0) { if (undo != null) { 259 260 UndoItem dirFirstItem = undo.fbItem; 262 int fbUndoMarkCount = 0; 263 264 267 while (dirFirstItem != null) { 268 if ((dirFirstItem.mark.flags & MultiMark.REMOVED) == 0) { fbUndoMarkCount++; 270 UndoItem item = dirFirstItem.logicalNext; 271 while (item != null) { 273 if ((item.mark.flags & MultiMark.REMOVED) == 0) { fbUndoMarkCount++; 275 } else { item.mark = null; 277 } 278 279 item = item.logicalNext; 280 } 281 break; 282 283 } else { dirFirstItem.mark = null; 285 } 286 287 dirFirstItem = dirFirstItem.logicalNext; 288 } 289 290 if (dirFirstItem != null) { MultiMark firstItemMark = dirFirstItem.mark; 293 int index = offsetGapIndex; 294 295 while (markArray[getRawIndex(index)] != firstItemMark) { 296 index++; 297 } 298 299 while (--index >= offsetGapIndex) { 300 markArray[getRawIndex(index + fbUndoMarkCount)] 301 = markArray[getRawIndex(index)]; 302 } 303 } 304 305 dirFirstItem = undo.bbItem; 306 int bbUndoMarkCount = 0; 307 308 311 while (dirFirstItem != null) { 312 if ((dirFirstItem.mark.flags & MultiMark.REMOVED) == 0) { bbUndoMarkCount++; 314 UndoItem item = dirFirstItem.logicalNext; 315 while (item != null) { 317 if ((item.mark.flags & MultiMark.REMOVED) == 0) { bbUndoMarkCount++; 319 } else { item.mark = null; 321 } 322 item = item.logicalNext; 323 } 324 break; 325 326 } else { dirFirstItem.mark = null; 328 } 329 330 dirFirstItem = dirFirstItem.logicalNext; 331 } 332 333 if (dirFirstItem != null) { MultiMark firstItemMark = dirFirstItem.mark; 336 int index = offsetGapIndex; 337 338 while (markArray[getRawIndex(--index)] != firstItemMark) { 339 } 340 index++; 341 342 while (index < offsetGapIndex) { 343 markArray[getRawIndex(index - bbUndoMarkCount)] 344 = markArray[getRawIndex(index)]; 345 index++; 346 } 347 } 348 349 350 UndoItem origItem = undo.firstItem; 351 354 offsetGapIndex -= bbUndoMarkCount; 355 while (origItem != null) { 356 MultiMark mark = origItem.mark; 357 if (mark != null) { 358 mark.rawOffset = origItem.undoOffset; 360 markArray[getRawIndex(offsetGapIndex++)] = mark; 361 } 362 363 origItem = origItem.next; 364 } 365 366 369 if (offset == 0) { 370 ZeroUndoItem zeroItem = undo.zeroItem; 371 while (zeroItem != null) { 372 MultiMark mark = zeroItem.mark; 373 if ((mark.flags & MultiMark.REMOVED) == 0) { 374 mark.flags &= ~MultiMark.ZERO; 375 } 376 zeroItem = zeroItem.next; 377 } 378 } 379 } 380 381 undo = null; 382 383 } else { 404 offset += length; UndoItem item = null; UndoItem fbItem = null; UndoItem bbItem = null; UndoItem upperBBItem = null; int upperBBMIndex = -1; int offsetAboveGap = offset + offsetGapLength; ZeroUndoItem zeroItem = null; 412 413 if (offset == 0) { 414 int offsetGapIndexCopy = offsetGapIndex; 415 int markCount = getMarkCount(); 416 while (offsetGapIndexCopy < markCount) { 417 MultiMark mark = markArray[getRawIndex(offsetGapIndexCopy++)]; 418 if (mark.rawOffset == offsetAboveGap) { 419 if ((mark.flags & (MultiMark.COMPATIBLE | MultiMark.ZERO)) 420 == MultiMark.COMPATIBLE 421 ) { 422 mark.flags |= MultiMark.ZERO; 423 zeroItem = new ZeroUndoItem(mark, zeroItem); 424 } 425 426 } else { break; 428 } 429 } 430 } 431 432 433 while (offsetGapIndex > 0) { 434 MultiMark mark = markArray[getRawIndex(--offsetGapIndex)]; 435 int markOffset = mark.rawOffset; boolean backwardBias = ((mark.flags & MultiMark.BACKWARD_BIAS) != 0); 437 if (markOffset < offset || (mark.rawOffset == offset && backwardBias) 439 ) { break; 441 } 442 443 item = new UndoItem(mark, markOffset, item); 444 445 if (backwardBias) { 446 if (bbItem != null) { 447 bbItem.logicalNext = item; 448 } else { upperBBItem = item; 450 upperBBMIndex = offsetGapIndex; 451 } 452 bbItem = item; 453 454 mark.rawOffset = offset; 456 457 } else { item.logicalNext = fbItem; 459 fbItem = item; 460 461 mark.rawOffset = offsetAboveGap; 463 464 if (upperBBMIndex >= 0) { int upperBBMRawIndex = getRawIndex(upperBBMIndex--); 467 markArray[getRawIndex(offsetGapIndex)] 468 = markArray[upperBBMRawIndex]; 469 470 markArray[upperBBMRawIndex] = mark; 471 472 UndoItem upperNext = upperBBItem.logicalNext; 473 if (upperNext != null) { 474 bbItem.logicalNext = upperBBItem; 475 bbItem = upperBBItem; 476 upperBBItem.logicalNext = null; 477 upperBBItem = upperNext; 478 } 479 } 480 } 481 } 482 483 487 if (offset == 0 && item != null) { 488 UndoItem i = item; 489 while (i != null) { 490 MultiMark mark = i.mark; 491 if ((mark.flags & (MultiMark.COMPATIBLE | MultiMark.ZERO)) 492 == MultiMark.COMPATIBLE 493 ) { 494 mark.flags |= MultiMark.ZERO; 495 zeroItem = new ZeroUndoItem(mark, zeroItem); 496 } 497 i = i.next; 498 } 499 } 500 501 undo = (item != null || zeroItem != null) 502 ? new Undo(item, fbItem, upperBBItem, zeroItem) 503 : null; 504 505 } 506 507 return undo; 508 } 509 510 private void removeDisposedMarks() { 511 int rawIndex = 0; 512 int validInd = -1; 513 int gapEnd = gapStart + gapLength; 514 515 while (rawIndex < gapStart) { 516 MultiMark mark = markArray[rawIndex]; 517 if ((mark.flags & MultiMark.VALID) != 0) { if (rawIndex != ++validInd) { 519 markArray[validInd] = mark; 520 } 521 522 } else { mark.flags |= MultiMark.REMOVED; 524 } 525 rawIndex++; 526 } 527 gapStart = validInd + 1; 528 529 rawIndex = markArray.length; 530 validInd = rawIndex; 531 while (--rawIndex >= gapEnd) { 532 MultiMark mark = markArray[rawIndex]; 533 if ((mark.flags & MultiMark.VALID) != 0) { if (rawIndex != --validInd) { 535 markArray[validInd] = mark; 536 } 537 538 } else { mark.flags |= MultiMark.REMOVED; 540 } 541 } 542 gapLength = validInd - gapStart; 543 544 disposedMarkCount = 0; 545 } 546 547 int getOffset(int rawOffset) { 548 552 return (rawOffset <= offsetGapStart) 553 ? rawOffset 554 : (rawOffset - offsetGapLength); 555 } 556 557 private int getRawIndex(int index) { 558 return (index < gapStart) 559 ? index 560 : index + gapLength; 561 } 562 563 573 private int findInsertIndex(int offset) { 574 int low = 0; 575 int high = getMarkCount() - 1; 576 577 while (low <= high) { 578 int index = (low + high) / 2; MultiMark mark = markArray[getRawIndex(index)]; 580 int markOffset = getOffset(mark.rawOffset); 581 582 if (markOffset < offset) { 583 low = index + 1; 584 585 } else if (markOffset > offset) { 586 high = index - 1; 587 588 } else { if ((mark.flags & MultiMark.BACKWARD_BIAS) != 0) { low = index + 1; 591 } else { high = index - 1; 593 } 594 } 595 } 596 597 return low; 598 } 599 600 private void moveGap(int index) { 601 if (index <= gapStart) { int moveSize = gapStart - index; 603 System.arraycopy(markArray, index, markArray, 604 gapStart + gapLength - moveSize, moveSize); 605 gapStart = index; 606 607 } else { int moveSize = index - gapStart; 609 System.arraycopy(markArray, gapStart + gapLength, markArray, gapStart, moveSize); 610 gapStart += moveSize; 611 } 612 } 613 614 private void moveOffsetGap(int index, int newOffsetGapStart) { 615 int rawIndex = getRawIndex(index); 616 int markArrayLength = markArray.length; 617 int offset = offsetGapStart; 618 offsetGapStart = newOffsetGapStart; 619 int length = offsetGapLength; 620 621 if (rawIndex == markArrayLength 622 || markArray[rawIndex].rawOffset > offset 623 ) { 625 int bound = (rawIndex < gapStart) 626 ? 0 627 : (gapStart + gapLength); 628 629 while (true) { 630 while (--rawIndex >= bound) { 631 MultiMark mark = markArray[rawIndex]; 632 if (mark.rawOffset > offset) { 633 mark.rawOffset -= length; 634 } 635 } 636 637 if (bound > 0) { bound = 0; 639 rawIndex = gapStart; 640 641 } else { break; 643 } 644 } 645 646 } else { 648 int bound = (rawIndex < gapStart) 649 ? gapStart 650 : markArrayLength; 651 652 while (true) { 653 while (rawIndex < bound) { 654 MultiMark mark = markArray[rawIndex]; 655 if (mark.rawOffset <= offset) { 656 mark.rawOffset += length; 657 } 658 rawIndex++; 659 } 660 661 if (bound < markArrayLength) { bound = markArrayLength; 663 rawIndex += gapLength; 664 665 } else { break; 667 } 668 } 669 670 } 671 } 672 673 private void enlargeGap(int extraLength) { 674 int newLength = Math.max(8, markArray.length * 3 / 2 + extraLength); 675 int gapEnd = gapStart + gapLength; 676 int afterGapLength = (markArray.length - gapEnd); 677 int newGapEnd = newLength - afterGapLength; 678 MultiMark[] newMarkArray = new MultiMark[newLength]; 679 System.arraycopy(markArray, 0, newMarkArray, 0, gapStart); 680 System.arraycopy(markArray, gapEnd, newMarkArray, newGapEnd, afterGapLength); 681 markArray = newMarkArray; 682 gapLength = newGapEnd - gapStart; 683 } 684 685 695 Object [] toObjects() { 696 return new Object [] { 697 markArray.clone(), 698 new Integer (gapStart), 699 new Integer (gapLength), 700 new Integer (offsetGapStart), 701 new Integer (offsetGapLength) 702 }; 703 } 704 705 706 public String toString() { 707 return "markCount=" + getMarkCount() + ", gapStart=" + gapStart + ", gapLength=" + gapLength + ", offsetGapStart=" + offsetGapStart + ", offsetGapLength=" + offsetGapLength; } 713 714 716 static final class Undo { 717 718 Undo(UndoItem firstItem, UndoItem fbItem, UndoItem bbItem, 719 ZeroUndoItem zeroItem) { 720 721 this.firstItem = firstItem; 722 this.fbItem = fbItem; 723 this.bbItem = bbItem; 724 this.zeroItem = zeroItem; 725 } 726 727 UndoItem firstItem; 728 729 UndoItem fbItem; 730 731 UndoItem bbItem; 732 733 ZeroUndoItem zeroItem; 734 735 } 736 737 741 static final class UndoItem { 742 743 UndoItem(MultiMark mark, int undoOffset, UndoItem next) { 744 this.mark = mark; 745 this.undoOffset = undoOffset; 746 this.next = next; 747 } 748 749 MultiMark mark; 750 751 int undoOffset; 752 753 UndoItem next; 754 755 UndoItem logicalNext; 756 757 } 758 759 static final class ZeroUndoItem { 760 761 ZeroUndoItem(MultiMark mark, ZeroUndoItem next) { 762 this.mark = mark; 763 this.next = next; 764 } 765 766 final MultiMark mark; 767 768 final ZeroUndoItem next; 769 770 } 771 772 } 773 | Popular Tags |