1616
1717package org .radarcns ;
1818
19+ import javax .annotation .Nonnull ;
1920import java .util .HashMap ;
21+ import java .util .Iterator ;
2022import java .util .Map ;
23+ import java .util .NoSuchElementException ;
24+ import java .util .SortedMap ;
2125import java .util .SortedSet ;
26+ import java .util .TreeMap ;
2227import java .util .TreeSet ;
2328
2429/** 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 ;
2732
2833 public OffsetRangeSet () {
29- ranges = new HashMap <>();
34+ ranges = new TreeMap <>();
3035 }
3136
3237 /** Add given offset range to seen offsets. */
3338 public void add (OffsetRange range ) {
3439 SortedSet <OffsetRange > topicRanges = ranges .computeIfAbsent (
35- range .getTopic () + '+' + range .getPartition (), k -> new TreeSet <>());
40+ key ( range .getTopic (), range .getPartition () ), k -> new TreeSet <>());
3641
3742 SortedSet <OffsetRange > tail = topicRanges .tailSet (range );
3843 SortedSet <OffsetRange > head = topicRanges .headSet (range );
3944
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 )) {
4250 return ;
4351 }
4452
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 );
4957 } else {
50- tail . first () .setOffsetFrom (range .getOffsetFrom ());
58+ next .setOffsetFrom (range .getOffsetFrom ());
5159 }
5260 return ;
5361 }
5462 }
5563
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 ());
5866 return ;
5967 }
6068
@@ -63,8 +71,7 @@ public void add(OffsetRange range) {
6371
6472 /** Whether this range set completely contains the given range. */
6573 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 ()));
6875 if (topicRanges == null ) {
6976 return false ;
7077 }
@@ -74,14 +81,26 @@ public boolean contains(OffsetRange range) {
7481 }
7582
7683 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 ()) {
8089 return true ;
8190 }
8291
8392 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+ }
85104 }
86105
87106 @ Override
@@ -93,4 +112,48 @@ public String toString() {
93112 public boolean isEmpty () {
94113 return ranges .isEmpty ();
95114 }
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+ }
96159}
0 commit comments