Skip to content

Commit 9d82adc

Browse files
committed
Make TokenStreamRewriter#reduceToSingleOperationPerIndex faster for large amount of rewrite operations
Signed-off-by: Sergey Nuyanzin <[email protected]>
1 parent bd8f993 commit 9d82adc

File tree

1 file changed

+54
-31
lines changed

1 file changed

+54
-31
lines changed

runtime/Java/src/org/antlr/v4/runtime/TokenStreamRewriter.java

Lines changed: 54 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import org.antlr.v4.runtime.misc.Interval;
99

1010
import java.util.ArrayList;
11+
import java.util.BitSet;
1112
import java.util.HashMap;
1213
import java.util.List;
1314
import java.util.Map;
@@ -478,32 +479,53 @@ public String getText(String programName, Interval interval) {
478479
protected Map<Integer, RewriteOperation> reduceToSingleOperationPerIndex(List<RewriteOperation> rewrites) {
479480
// System.out.println("rewrites="+rewrites);
480481

482+
// BitSets are used here to track ReplaceOps and InsertBeforeOps
483+
final BitSet replaceOpSet = new BitSet(rewrites.size());
484+
final BitSet insertBeforeSet = new BitSet(rewrites.size());
485+
481486
// WALK REPLACES
482487
for (int i = 0; i < rewrites.size(); i++) {
483488
RewriteOperation op = rewrites.get(i);
484-
if ( op==null ) continue;
485-
if ( !(op instanceof ReplaceOp) ) continue;
489+
if ( op==null ){
490+
continue;
491+
}
492+
if ( !(op instanceof ReplaceOp) ) {
493+
if (op instanceof InsertBeforeOp) {
494+
insertBeforeSet.set(i);
495+
}
496+
continue;
497+
}
486498
ReplaceOp rop = (ReplaceOp)rewrites.get(i);
499+
replaceOpSet.set(i);
500+
487501
// Wipe prior inserts within range
488-
List<? extends InsertBeforeOp> inserts = getKindOfOps(rewrites, InsertBeforeOp.class, i);
489-
for (InsertBeforeOp iop : inserts) {
502+
for (int j = insertBeforeSet.nextSetBit(0); j >= 0&& j < i; j = insertBeforeSet.nextSetBit(j + 1)) {
503+
RewriteOperation roj = rewrites.get(j);
504+
InsertBeforeOp iop = (InsertBeforeOp) roj;
490505
if ( iop.index == rop.index ) {
491506
// E.g., insert before 2, delete 2..2; update replace
492507
// text to include insert before, kill insert
493508
rewrites.set(iop.instructionIndex, null);
509+
replaceOpSet.clear(iop.instructionIndex);
510+
insertBeforeSet.clear(iop.instructionIndex);
494511
rop.text = iop.text.toString() + (rop.text!=null?rop.text.toString():"");
495512
}
496513
else if ( iop.index > rop.index && iop.index <= rop.lastIndex ) {
497514
// delete insert as it's a no-op.
498515
rewrites.set(iop.instructionIndex, null);
516+
replaceOpSet.clear(iop.instructionIndex);
517+
insertBeforeSet.clear(iop.instructionIndex);
499518
}
500519
}
501520
// Drop any prior replaces contained within
502-
List<? extends ReplaceOp> prevReplaces = getKindOfOps(rewrites, ReplaceOp.class, i);
503-
for (ReplaceOp prevRop : prevReplaces) {
521+
for (int j = replaceOpSet.nextSetBit(0); j >=0 && j < i; j = replaceOpSet.nextSetBit(j + 1)) {
522+
RewriteOperation roj = rewrites.get(j);
523+
ReplaceOp prevRop = (ReplaceOp) roj;
504524
if ( prevRop.index>=rop.index && prevRop.lastIndex <= rop.lastIndex ) {
505525
// delete replace as it's a no-op.
506526
rewrites.set(prevRop.instructionIndex, null);
527+
replaceOpSet.clear(prevRop.instructionIndex);
528+
insertBeforeSet.clear(prevRop.instructionIndex);
507529
continue;
508530
}
509531
// throw exception unless disjoint or identical
@@ -514,9 +536,11 @@ else if ( iop.index > rop.index && iop.index <= rop.lastIndex ) {
514536
if ( prevRop.text==null && rop.text==null && !disjoint ) {
515537
//System.out.println("overlapping deletes: "+prevRop+", "+rop);
516538
rewrites.set(prevRop.instructionIndex, null); // kill first delete
539+
replaceOpSet.clear(prevRop.instructionIndex);
540+
insertBeforeSet.clear(prevRop.instructionIndex);
517541
rop.index = Math.min(prevRop.index, rop.index);
518542
rop.lastIndex = Math.max(prevRop.lastIndex, rop.lastIndex);
519-
System.out.println("new rop "+rop);
543+
//System.out.println("new rop "+rop);
520544
}
521545
else if ( !disjoint ) {
522546
throw new IllegalArgumentException("replace op boundaries of "+rop+" overlap with previous "+prevRop);
@@ -528,31 +552,44 @@ else if ( !disjoint ) {
528552
for (int i = 0; i < rewrites.size(); i++) {
529553
RewriteOperation op = rewrites.get(i);
530554
if ( op==null ) continue;
531-
if ( !(op instanceof InsertBeforeOp) ) continue;
555+
if ( !(op instanceof InsertBeforeOp) ) {
556+
if (op instanceof ReplaceOp) {
557+
replaceOpSet.set(i);
558+
}
559+
continue;
560+
}
561+
insertBeforeSet.set(i);
532562
InsertBeforeOp iop = (InsertBeforeOp)rewrites.get(i);
533563
// combine current insert with prior if any at same index
534-
List<? extends InsertBeforeOp> prevInserts = getKindOfOps(rewrites, InsertBeforeOp.class, i);
535-
for (InsertBeforeOp prevIop : prevInserts) {
564+
565+
for (int j = insertBeforeSet.nextSetBit(0); j >= 0&& j < i; j = insertBeforeSet.nextSetBit(j + 1)) {
566+
InsertBeforeOp prevIop = (InsertBeforeOp) rewrites.get(j);
536567
if ( prevIop.index==iop.index ) {
537-
if ( InsertAfterOp.class.isInstance(prevIop) ) {
568+
if (prevIop instanceof InsertAfterOp) {
538569
iop.text = catOpText(prevIop.text, iop.text);
539570
rewrites.set(prevIop.instructionIndex, null);
571+
insertBeforeSet.clear(prevIop.instructionIndex);
572+
replaceOpSet.clear(prevIop.instructionIndex);
540573
}
541-
else if ( InsertBeforeOp.class.isInstance(prevIop) ) { // combine objects
574+
else { // combine objects
542575
// convert to strings...we're in process of toString'ing
543576
// whole token buffer so no lazy eval issue with any templates
544577
iop.text = catOpText(iop.text, prevIop.text);
545578
// delete redundant prior insert
546579
rewrites.set(prevIop.instructionIndex, null);
580+
insertBeforeSet.clear(prevIop.instructionIndex);
581+
replaceOpSet.clear(prevIop.instructionIndex);
547582
}
548583
}
549584
}
550585
// look for replaces where iop.index is in range; error
551-
List<? extends ReplaceOp> prevReplaces = getKindOfOps(rewrites, ReplaceOp.class, i);
552-
for (ReplaceOp rop : prevReplaces) {
586+
for (int j = replaceOpSet.nextSetBit(0); j >= 0&& j < i; j = replaceOpSet.nextSetBit(j + 1)) {
587+
ReplaceOp rop = (ReplaceOp) rewrites.get(j);
553588
if ( iop.index == rop.index ) {
554589
rop.text = catOpText(iop.text,rop.text);
555590
rewrites.set(i, null); // delete current insert
591+
insertBeforeSet.clear(i);
592+
replaceOpSet.clear(i);
556593
continue;
557594
}
558595
if ( iop.index >= rop.index && iop.index <= rop.lastIndex ) {
@@ -562,13 +599,12 @@ else if ( InsertBeforeOp.class.isInstance(prevIop) ) { // combine objects
562599
}
563600
// System.out.println("rewrites after="+rewrites);
564601
Map<Integer, RewriteOperation> m = new HashMap<Integer, RewriteOperation>();
565-
for (int i = 0; i < rewrites.size(); i++) {
566-
RewriteOperation op = rewrites.get(i);
602+
for (int k = 0; k < rewrites.size(); k++) {
603+
RewriteOperation op = rewrites.get(k);
567604
if ( op==null ) continue; // ignore deleted ops
568-
if ( m.get(op.index)!=null ) {
605+
if ( m.put(op.index, op)!=null ) {
569606
throw new Error("should only be one op per index");
570607
}
571-
m.put(op.index, op);
572608
}
573609
//System.out.println("index to op: "+m);
574610
return m;
@@ -581,17 +617,4 @@ protected String catOpText(Object a, Object b) {
581617
if ( b!=null ) y = b.toString();
582618
return x+y;
583619
}
584-
585-
/** Get all operations before an index of a particular kind */
586-
protected <T extends RewriteOperation> List<? extends T> getKindOfOps(List<? extends RewriteOperation> rewrites, Class<T> kind, int before) {
587-
List<T> ops = new ArrayList<T>();
588-
for (int i=0; i<before && i<rewrites.size(); i++) {
589-
RewriteOperation op = rewrites.get(i);
590-
if ( op==null ) continue; // ignore deleted
591-
if ( kind.isInstance(op) ) {
592-
ops.add(kind.cast(op));
593-
}
594-
}
595-
return ops;
596-
}
597620
}

0 commit comments

Comments
 (0)