Skip to content

Commit cfe9428

Browse files
committed
Lots of changes for 0.10 release
1 parent eaedde0 commit cfe9428

File tree

16 files changed

+575
-39
lines changed

16 files changed

+575
-39
lines changed

BEXCodeCompare/src/main/java/info/codesaway/bex/BEXPair.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@
1818
* Pair of left and right values, which are of the same type
1919
*
2020
* <p>Instances of this class are immutable if generic class type is also immutable</p>
21+
*
22+
* <p>Instances of this class are Comparable if generic class type is also Comparable</p>
2123
* @param <T> the type of pair
2224
* @since 0.3
2325
*/
24-
public interface BEXPair<T> {
26+
public interface BEXPair<T> extends Comparable<BEXPair<T>> {
2527
/**
2628
* Gets the left value in the pair
2729
* @return the left value
@@ -256,4 +258,24 @@ public default void acceptWithSide(final BiConsumer<T, BEXSide> consumer) {
256258
public default String toString(final String format) {
257259
return String.format(format, this.getLeft(), this.getRight());
258260
}
261+
262+
/**
263+
* Compares the BEXPair first by the left element then the right element
264+
* @throws ClassCastException if the entries do not implement Comparable or are not mutually Comparable
265+
*/
266+
@Override
267+
public default int compareTo(final BEXPair<T> o) {
268+
@SuppressWarnings("unchecked")
269+
Comparable<? super T> left1 = (Comparable<? super T>) this.getLeft();
270+
271+
@SuppressWarnings("unchecked")
272+
Comparable<? super T> right1 = (Comparable<? super T>) this.getRight();
273+
274+
int compare = left1.compareTo(o.getLeft());
275+
if (compare != 0) {
276+
return compare;
277+
}
278+
279+
return right1.compareTo(o.getRight());
280+
}
259281
}

BEXCodeCompare/src/main/java/info/codesaway/bex/BEXPairs.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,18 @@ private BEXPairs() {
99
throw new UnsupportedOperationException();
1010
}
1111

12+
/**
13+
*
14+
* @param <T> the type
15+
* @param left the left value
16+
* @param right the right value
17+
* @return a BEXPair with the specified left / right values
18+
* @since 0.10
19+
*/
20+
public static <T> BEXPair<T> bexPair(final T left, final T right) {
21+
return new BEXPairValue<>(left, right);
22+
}
23+
1224
public static <K, V> BEXPair<V> mapGet(final BEXPair<? extends Map<K, V>> mapPair,
1325
final BEXPair<K> keyPair) {
1426
return mapPair.mapWithSide((m, side) -> m.get(keyPair.get(side)));

BEXCodeCompare/src/main/java/info/codesaway/bex/IntBEXRange.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ private IntBEXRange(final int start, final int end, final boolean hasInclusiveEn
2929
if (end < start) {
3030
throw new IllegalArgumentException(String.format("Invalid range start = %d, end = %d", start, end));
3131
}
32+
33+
if (end == start && !hasInclusiveStart && !hasInclusiveEnd) {
34+
// Mimics Guava's Range class and throws exception
35+
throw new IllegalArgumentException(String.format("Invalid range (%d, %d)", start, end));
36+
}
3237
}
3338

3439
/**

BEXCodeCompare/src/main/java/info/codesaway/bex/IntRange.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,19 @@ public default boolean isEmpty() {
3838
&& !(this.hasInclusiveStart() && this.hasInclusiveEnd());
3939
}
4040

41+
/**
42+
*
43+
* @return the length of the range
44+
* @since 0.10
45+
*/
46+
public default int length() {
47+
// Logic from canonical
48+
int start = this.hasInclusiveStart() ? this.getStart() : this.getStart() + 1;
49+
int end = this.hasInclusiveEnd() ? this.getEnd() + 1 : this.getEnd();
50+
51+
return end - start;
52+
}
53+
4154
public default IntRange canonical() {
4255
if (this.hasInclusiveStart() && !this.hasInclusiveEnd()) {
4356
return this;

BEXCodeCompare/src/main/java/info/codesaway/bex/matching/BEXMatchResult.java

Lines changed: 80 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,48 +5,107 @@
55
import java.util.Map.Entry;
66
import java.util.Set;
77

8-
import info.codesaway.bex.IntPair;
8+
import info.codesaway.bex.IntBEXRange;
99

1010
public interface BEXMatchResult {
1111
public BEXPattern pattern();
1212

1313
public String text();
1414

15-
public IntPair startEndPair();
15+
/**
16+
*
17+
* @return
18+
* @throws IllegalStateException
19+
* If no match has yet been attempted,
20+
* or if the previous match operation failed
21+
*/
22+
public IntBEXRange range();
1623

24+
/**
25+
*
26+
* @return
27+
* @throws IllegalStateException
28+
* If no match has yet been attempted,
29+
* or if the previous match operation failed
30+
*/
1731
public default int start() {
18-
return this.startEndPair().getLeft();
32+
return this.range().getStart();
1933
}
2034

35+
/**
36+
*
37+
* @return
38+
* @throws IllegalStateException
39+
* If no match has yet been attempted,
40+
* or if the previous match operation failed
41+
*/
2142
public default int end() {
22-
return this.startEndPair().getRight();
43+
return this.range().getEnd();
2344
}
2445

46+
/**
47+
*
48+
* @return
49+
* @throws IllegalStateException
50+
* If no match has yet been attempted,
51+
* or if the previous match operation failed
52+
*/
2553
public default String group() {
26-
return getSubstring(this.text(), this.startEndPair());
54+
return getSubstring(this.text(), this.range());
2755
}
2856

29-
public IntPair startEndPair(String group);
57+
/**
58+
*
59+
* @param group
60+
* @return
61+
* @throws IllegalStateException
62+
* If no match has yet been attempted,
63+
* or if the previous match operation failed
64+
*/
65+
public IntBEXRange range(String group);
3066

67+
/**
68+
*
69+
* @param group
70+
* @return
71+
* @throws IllegalStateException
72+
* If no match has yet been attempted,
73+
* or if the previous match operation failed
74+
*/
3175
public default int start(final String group) {
32-
return this.startEndPair(group).getLeft();
76+
return this.range(group).getStart();
3377
}
3478

79+
/**
80+
*
81+
* @param group
82+
* @throws IllegalStateException
83+
* If no match has yet been attempted,
84+
* or if the previous match operation failed
85+
*/
3586
public default int end(final String group) {
36-
return this.startEndPair(group).getRight();
87+
return this.range(group).getEnd();
3788
}
3889

90+
/**
91+
*
92+
* @param group
93+
* @return
94+
* @throws IllegalStateException
95+
* If no match has yet been attempted,
96+
* or if the previous match operation failed
97+
*/
3998
public default String group(final String group) {
4099
if (group.equals("*")) {
41100
return this.group();
42101
}
43102

44-
IntPair startEndPair = this.startEndPair(group);
45-
if (startEndPair.getLeft() == -1 || startEndPair.getRight() == -1) {
103+
IntBEXRange range = this.range(group);
104+
if (range.getStart() == -1 || range.getEnd() == -1) {
46105
return null;
47106
}
48107

49-
return getSubstring(this.text(), startEndPair);
108+
return getSubstring(this.text(), range);
50109
}
51110

52111
/**
@@ -61,10 +120,20 @@ public default String group(final String group) {
61120
*
62121
* @throws IllegalArgumentException
63122
* If the group is not specified in the pattern
123+
* @throws IllegalStateException
124+
* If no match has yet been attempted,
125+
* or if the previous match operation failed
64126
*/
65127
public default String get(final String group) {
66128
return this.group(group);
67129
}
68130

131+
/**
132+
*
133+
* @return
134+
* @throws IllegalStateException
135+
* If no match has yet been attempted,
136+
* or if the previous match operation failed
137+
*/
69138
public Set<Entry<String, String>> entrySet();
70139
}

BEXCodeCompare/src/main/java/info/codesaway/bex/matching/BEXMatcher.java

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public final class BEXMatcher implements BEXMatchResult {
6161
*/
6262
private int offset;
6363

64-
private final MutableIntBEXPair matchStartEnd = new MutableIntBEXPair(-1, 0);
64+
private final MutableIntBEXPair matchRange = new MutableIntBEXPair(-1, 0);
6565

6666
/**
6767
* Most groups will have only one value, so stored here
@@ -105,7 +105,7 @@ public BEXPattern pattern() {
105105
*/
106106
public BEXMatchResult toMatchResult() {
107107
BEXMatcher result = new BEXMatcher(this.pattern(), this.text(), this.textStateMap, this.offset);
108-
result.matchStartEnd.set(this.matchStartEnd);
108+
result.matchRange.set(this.matchRange);
109109
result.valuesMap.putAll(this.valuesMap);
110110

111111
if (!this.multipleValuesMap.isEmpty()) {
@@ -129,8 +129,8 @@ private void clearGroups() {
129129

130130
public boolean find() {
131131
// Logic from regex Matcher.find
132-
int nextSearchStart = this.end();
133-
if (nextSearchStart == this.start()) {
132+
int nextSearchStart = this.matchRange.getRight();
133+
if (nextSearchStart == this.matchRange.getLeft()) {
134134
nextSearchStart++;
135135
}
136136
// If next search starts beyond region then it fails
@@ -148,7 +148,7 @@ private boolean search(final int from) {
148148

149149
boolean foundMatch = this.match(from);
150150
if (!foundMatch) {
151-
this.matchStartEnd.setLeft(-1);
151+
this.matchRange.setLeft(-1);
152152
}
153153

154154
return foundMatch;
@@ -362,13 +362,13 @@ private boolean match(final int from) {
362362
// (unless it's an unnamed group)
363363
if (!group.equals("_")) {
364364
// TODO: what if group was matched as part of regex, does normal group have to match?
365-
IntBEXRange startEnd = this.getInternal(group);
365+
IntBEXRange range = this.getInternalNoMatchCheck(group);
366366

367367
// If group is already specified
368-
if (startEnd != null && startEnd != NOT_FOUND) {
368+
if (range != null && range != NOT_FOUND) {
369369
// Verify the content equals; otherwise, don't match
370370
// TODO: should go to next match or something... need to implement
371-
int oldLength = startEnd.getRight() - startEnd.getLeft();
371+
int oldLength = range.length();
372372
int newLength = end - start;
373373

374374
// Fast check, based on length
@@ -377,7 +377,7 @@ private boolean match(final int from) {
377377
}
378378

379379
// Compare character by character
380-
int index1 = startEnd.getLeft();
380+
int index1 = range.getStart();
381381
int index2 = start;
382382

383383
for (int m = 0; m < oldLength; m++) {
@@ -402,10 +402,10 @@ private boolean match(final int from) {
402402
int matchStart = currentMatcher.start();
403403
int matchEnd = regionStart;
404404

405-
this.matchStartEnd.set(matchStart, matchEnd);
405+
this.matchRange.set(matchStart, matchEnd);
406406

407407
if (DEBUG) {
408-
System.out.println("Found match: " + this.matchStartEnd);
408+
System.out.println("Found match: " + this.matchRange);
409409
}
410410

411411
return true;
@@ -458,7 +458,7 @@ private BEXMatchingState search(final int start, final int end,
458458
if (entry != null && !entry.getValue().isCode()) {
459459
// Has a state option
460460
IntRange canonical = entry.getKey().canonical();
461-
boolean isEndOfRange = indexWithOffset == canonical.getRight() - 1;
461+
boolean isEndOfRange = indexWithOffset == canonical.getEnd() - 1;
462462

463463
stateOption = isEndOfRange ? null : entry.getValue();
464464

@@ -554,26 +554,33 @@ private void put(final String group, final IntBEXRange value) {
554554
}
555555

556556
@Override
557-
public IntBEXRange startEndPair() {
558-
return IntBEXRange.of(this.matchStartEnd.getLeft(), this.matchStartEnd.getRight());
557+
public IntBEXRange range() {
558+
this.checkForMatch();
559+
560+
return IntBEXRange.of(this.matchRange.getLeft(), this.matchRange.getRight());
559561
}
560562

561563
@Override
562-
public IntBEXRange startEndPair(final String group) {
563-
IntBEXRange startEnd = this.getInternal(group);
564+
public IntBEXRange range(final String group) {
565+
IntBEXRange range = this.getInternal(group);
564566

565567
// Intentionally using identity equals
566-
if (startEnd == NOT_FOUND) {
568+
if (range == NOT_FOUND) {
567569
throw new IllegalArgumentException("The specified group is not in the pattern: " + group);
568570
}
569571

570-
return startEnd;
572+
return range;
571573
}
572574

573575
private static IntBEXRange NOT_FOUND = IntBEXRange.of(Integer.MIN_VALUE, Integer.MIN_VALUE);
574576
private static IntBEXRange NULL_PAIR = IntBEXRange.of(-1, -1);
575577

576578
private IntBEXRange getInternal(final String group) {
579+
this.checkForMatch();
580+
return this.getInternalNoMatchCheck(group);
581+
}
582+
583+
private IntBEXRange getInternalNoMatchCheck(final String group) {
577584
List<IntBEXRange> existingValues = this.multipleValuesMap.get(group);
578585

579586
if (existingValues != null) {
@@ -597,7 +604,7 @@ private IntBEXRange getInternal(final String group) {
597604
* @since 0.6
598605
*/
599606
public BEXMatcher reset() {
600-
this.matchStartEnd.set(-1, 0);
607+
this.matchRange.set(-1, 0);
601608
this.clearGroups();
602609
this.lastAppendPosition = 0;
603610

@@ -921,6 +928,7 @@ public StringBuffer appendTail(final StringBuffer sb) {
921928
*/
922929
@Override
923930
public Set<Entry<String, String>> entrySet() {
931+
this.checkForMatch();
924932
return new EntrySet();
925933
}
926934

@@ -933,6 +941,19 @@ private int getTextLength() {
933941
return this.text.length();
934942
}
935943

944+
/**
945+
* Check for match
946+
*
947+
* @throws IllegalStateException
948+
* If no match has yet been attempted,
949+
* or if the previous match operation failed
950+
*/
951+
private void checkForMatch() {
952+
if (this.matchRange.getLeft() < 0) {
953+
throw new IllegalStateException("No match available");
954+
}
955+
}
956+
936957
/**
937958
* Returns a literal replacement <code>String</code> for the specified
938959
* <code>String</code>.

0 commit comments

Comments
 (0)