1818 */
1919@ Singleton
2020class CommonPrefixGrouper implements ItemGrouper , ExpansionProvider {
21- public static final int MINIMUM_GROUP_LENGTH = 3 ;
21+ static final int MINIMUM_GROUP_LENGTH = 3 ;
2222 private final TimeTrackingItemQueries queries ;
2323 private final CommonPrefixGrouperConfig config ;
2424 private boolean initialized ;
2525 private PrefixTree root = new PrefixTree ();
2626
2727 @ Inject
28- public CommonPrefixGrouper (TimeTrackingItemQueries queries ,
29- CommonPrefixGrouperConfig config ) {
28+ CommonPrefixGrouper (TimeTrackingItemQueries queries ,
29+ CommonPrefixGrouperConfig config ) {
3030 this .queries = Objects .requireNonNull (queries );
3131 this .config = Objects .requireNonNull (config );
3232 }
@@ -35,42 +35,7 @@ public CommonPrefixGrouper(TimeTrackingItemQueries queries,
3535 public List <Group > getGroupsOf (String text ) {
3636 Objects .requireNonNull (text );
3737 checkInitialized ();
38- ArrayList <Group > groups = new ArrayList <>();
39- char [] chars = text .toCharArray ();
40- int n = chars .length ;
41- PrefixTree node = root ;
42- int i = 0 ;
43- int start = 0 ;
44- while (i < n && node != null ) {
45- int lastGood = i ;
46- do {
47- if (!Character .isWhitespace (chars [i ])) {
48- lastGood = i ;
49- }
50- node = node .child (chars [i ]);
51- i ++;
52- } while (i < n && node != null && node .numChildren () <= 1 );
53- do {
54- if (lastGood >= i && node != null ) {
55- node = node .child (chars [i ]);
56- i ++;
57- }
58- lastGood ++;
59- }
60- while (lastGood < n && (!Character .isWhitespace (chars [lastGood ]) || lastGood - start < 3 ));
61- groups .add (new Group (Type .MATCH , text .substring (start , lastGood ), new IntRange (start , lastGood )));
62- while (i < n && Character .isWhitespace (chars [i ])) {
63- if (node != null ) {
64- node = node .child (chars [i ]);
65- }
66- i ++;
67- }
68- start = i ;
69- }
70- if (i < n ) {
71- groups .add (new Group (Type .REMAINDER , text .substring (i , n ), new IntRange (i , n )));
72- }
73- return groups ;
38+ return new GroupHelper (text , root ).parse ();
7439 }
7540
7641 private void checkInitialized () {
@@ -91,7 +56,7 @@ private void checkInitialized() {
9156 stopWatch .stop ();
9257 }
9358
94- public void insert (String item ) {
59+ void insert (String item ) {
9560 PrefixTree node = root ;
9661 int i = 0 ;
9762 int n = item .length ();
@@ -155,30 +120,93 @@ public String toString() {
155120 private static class PrefixTree {
156121 private Map <Character , PrefixTree > child ;
157122
158- protected PrefixTree child (Character c ) {
123+ PrefixTree child (Character c ) {
159124 if (child == null ) {
160125 child = new HashMap <>();
161126 }
162127 return child .get (c );
163128 }
164129
165- public void child (Character c , PrefixTree newChild ) {
130+ void child (Character c , PrefixTree newChild ) {
166131 if (child == null ) {
167132 child = new HashMap <>();
168133 }
169134 child .put (c , newChild );
170135 }
171136
172- public int numChildren () {
137+ int numChildren () {
173138 return child == null ? 0 : child .size ();
174139 }
175140
176- public Character anyChild () {
141+ Character anyChild () {
177142 return child .keySet ().iterator ().next ();
178143 }
179144
180- public Set <Map .Entry <Character , PrefixTree >> allChildren () {
145+ Set <Map .Entry <Character , PrefixTree >> allChildren () {
181146 return child == null ? Collections .emptySet () : child .entrySet ();
182147 }
183148 }
149+
150+ private static class GroupHelper {
151+ private final String text ;
152+ private final List <Group > groups = new ArrayList <>();
153+ private final char [] chars ;
154+ private final int n ;
155+ private PrefixTree node ;
156+ private int i = 0 ;
157+ private int start = 0 ;
158+ private int lastGood ;
159+
160+ GroupHelper (String text , PrefixTree root ) {
161+ this .text = text ;
162+ this .chars = text .toCharArray ();
163+ this .n = chars .length ;
164+ this .node = root ;
165+ }
166+
167+ public List <Group > parse () {
168+ while (i < n && node != null ) {
169+ lastGood = start ;
170+ parseToNextBranch ();
171+ setLastGoodToNextWhitespace ();
172+ i = Math .max (i , lastGood );
173+ skipWhitespace ();
174+ groups .add (new Group (Type .MATCH , text .substring (start , lastGood ), new IntRange (start , lastGood )));
175+ start = i ;
176+ }
177+ if (start < n ) {
178+ groups .add (new Group (Type .REMAINDER , text .substring (start , n ), new IntRange (start , n )));
179+ }
180+ return groups ;
181+ }
182+
183+ private void skipWhitespace () {
184+ while (i < n && Character .isWhitespace (chars [i ])) {
185+ if (node != null ) {
186+ node = node .child (chars [i ]);
187+ }
188+ i ++;
189+ }
190+ }
191+
192+ private void setLastGoodToNextWhitespace () {
193+ do {
194+ if (lastGood >= i && node != null ) {
195+ node = node .child (chars [lastGood ]);
196+ }
197+ lastGood ++;
198+ }
199+ while (lastGood < n && (!Character .isWhitespace (chars [lastGood ]) || lastGood - start < MINIMUM_GROUP_LENGTH ));
200+ }
201+
202+ private void parseToNextBranch () {
203+ do {
204+ if (!Character .isWhitespace (chars [i ])) {
205+ lastGood = i ;
206+ }
207+ node = node .child (chars [i ]);
208+ i ++;
209+ } while (i < n && node != null && node .numChildren () <= 1 );
210+ }
211+ }
184212}
0 commit comments