16
16
17
17
package org .radarcns ;
18
18
19
+ import javax .annotation .Nonnull ;
19
20
import java .util .HashMap ;
21
+ import java .util .Iterator ;
20
22
import java .util .Map ;
23
+ import java .util .NoSuchElementException ;
24
+ import java .util .SortedMap ;
21
25
import java .util .SortedSet ;
26
+ import java .util .TreeMap ;
22
27
import java .util .TreeSet ;
23
28
24
29
/** Encompasses a range of offsets. */
25
- public class OffsetRangeSet {
26
- private final Map <String , SortedSet <OffsetRange >> ranges ;
30
+ public class OffsetRangeSet implements Iterable < OffsetRange > {
31
+ private final SortedMap <String , SortedSet <OffsetRange >> ranges ;
27
32
28
33
public OffsetRangeSet () {
29
- ranges = new HashMap <>();
34
+ ranges = new TreeMap <>();
30
35
}
31
36
32
37
/** Add given offset range to seen offsets. */
33
38
public void add (OffsetRange range ) {
34
39
SortedSet <OffsetRange > topicRanges = ranges .computeIfAbsent (
35
- range .getTopic () + '+' + range .getPartition (), k -> new TreeSet <>());
40
+ key ( range .getTopic (), range .getPartition () ), k -> new TreeSet <>());
36
41
37
42
SortedSet <OffsetRange > tail = topicRanges .tailSet (range );
38
43
SortedSet <OffsetRange > head = topicRanges .headSet (range );
39
44
40
- if (!tail .isEmpty ()) {
41
- if (tail .first ().equals (range )) {
45
+ OffsetRange next = !tail .isEmpty () ? tail .first () : null ;
46
+ OffsetRange previous = !head .isEmpty () ? head .last () : null ;
47
+
48
+ if (next != null ) {
49
+ if (next .equals (range )) {
42
50
return ;
43
51
}
44
52
45
- if (tail . first () .getOffsetFrom () <= range .getOffsetTo () + 1 ) {
46
- if (! head . isEmpty () && head . last () .getOffsetTo () >= range .getOffsetFrom () - 1 ) {
47
- tail . first (). setOffsetFrom (head . last () .getOffsetFrom ());
48
- topicRanges .remove (head . last () );
53
+ if (next .getOffsetFrom () <= range .getOffsetTo () + 1 ) {
54
+ if (previous != null && previous .getOffsetTo () >= range .getOffsetFrom () - 1 ) {
55
+ next . setOffsetFrom (previous .getOffsetFrom ());
56
+ topicRanges .remove (previous );
49
57
} else {
50
- tail . first () .setOffsetFrom (range .getOffsetFrom ());
58
+ next .setOffsetFrom (range .getOffsetFrom ());
51
59
}
52
60
return ;
53
61
}
54
62
}
55
63
56
- if (! head . isEmpty () && head . last () .getOffsetTo () >= range .getOffsetFrom () - 1 ) {
57
- head . last () .setOffsetTo (range .getOffsetTo ());
64
+ if (previous != null && previous .getOffsetTo () >= range .getOffsetFrom () - 1 ) {
65
+ previous .setOffsetTo (range .getOffsetTo ());
58
66
return ;
59
67
}
60
68
@@ -63,8 +71,7 @@ public void add(OffsetRange range) {
63
71
64
72
/** Whether this range set completely contains the given range. */
65
73
public boolean contains (OffsetRange range ) {
66
- String key = range .getTopic () + '+' + range .getPartition ();
67
- SortedSet <OffsetRange > topicRanges = ranges .get (key );
74
+ SortedSet <OffsetRange > topicRanges = ranges .get (key (range .getTopic (), range .getPartition ()));
68
75
if (topicRanges == null ) {
69
76
return false ;
70
77
}
@@ -74,14 +81,26 @@ public boolean contains(OffsetRange range) {
74
81
}
75
82
76
83
SortedSet <OffsetRange > tail = topicRanges .tailSet (range );
77
- if (!tail .isEmpty ()
78
- && tail .first ().getOffsetFrom () == range .getOffsetFrom ()
79
- && tail .first ().getOffsetTo () >= range .getOffsetTo ()) {
84
+ OffsetRange next = !tail .isEmpty () ? tail .first () : null ;
85
+
86
+ if (next != null
87
+ && next .getOffsetFrom () == range .getOffsetFrom ()
88
+ && next .getOffsetTo () >= range .getOffsetTo ()) {
80
89
return true ;
81
90
}
82
91
83
92
SortedSet <OffsetRange > head = topicRanges .headSet (range );
84
- return !head .isEmpty () && head .last ().getOffsetTo () >= range .getOffsetTo ();
93
+ OffsetRange previous = !head .isEmpty () ? head .last () : null ;
94
+ return previous != null && previous .getOffsetTo () >= range .getOffsetTo ();
95
+ }
96
+
97
+ public int size (String topic , int partition ) {
98
+ SortedSet <OffsetRange > rangeSet = ranges .get (key (topic , partition ));
99
+ if (rangeSet != null ) {
100
+ return rangeSet .size ();
101
+ } else {
102
+ return 0 ;
103
+ }
85
104
}
86
105
87
106
@ Override
@@ -93,4 +112,48 @@ public String toString() {
93
112
public boolean isEmpty () {
94
113
return ranges .isEmpty ();
95
114
}
115
+
116
+ private static String key (String topic , int partition ) {
117
+ return topic + '+' + partition ;
118
+ }
119
+
120
+ @ Override
121
+ @ Nonnull
122
+ public Iterator <OffsetRange > iterator () {
123
+ final Iterator <SortedSet <OffsetRange >> partitionIterator = ranges .values ().iterator ();
124
+ return new Iterator <OffsetRange >() {
125
+ Iterator <OffsetRange > rangeIterator ;
126
+ @ Override
127
+ public boolean hasNext () {
128
+ while (rangeIterator == null || !rangeIterator .hasNext ()) {
129
+ if (!partitionIterator .hasNext ()) {
130
+ return false ;
131
+ }
132
+ rangeIterator = partitionIterator .next ().iterator ();
133
+ }
134
+ return rangeIterator .hasNext ();
135
+ }
136
+
137
+ @ Override
138
+ public OffsetRange next () {
139
+ if (!hasNext ()) {
140
+ throw new NoSuchElementException ();
141
+ }
142
+ return rangeIterator .next ();
143
+ }
144
+ };
145
+ }
146
+
147
+ @ Override
148
+ public boolean equals (Object o ) {
149
+ return o == this
150
+ || o != null
151
+ && getClass ().equals (o .getClass ())
152
+ && ranges .equals (((OffsetRangeSet ) o ).ranges );
153
+ }
154
+
155
+ @ Override
156
+ public int hashCode () {
157
+ return ranges .hashCode ();
158
+ }
96
159
}
0 commit comments