1993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira/* 2993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Copyright (C) 2009 Google Inc. 3993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 4993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Licensed under the Apache License, Version 2.0 (the "License"); 5993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * you may not use this file except in compliance with the License. 6993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * You may obtain a copy of the License at 7993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 8993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * http://www.apache.org/licenses/LICENSE-2.0 9993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 10993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Unless required by applicable law or agreed to in writing, software 11993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * distributed under the License is distributed on an "AS IS" BASIS, 12993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * See the License for the specific language governing permissions and 14993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * limitations under the License. 15993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 16993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 171bdbfefe4b144c7b031a1d9242a0fa061a0ae6b5Scott Kennedypackage com.google.android.mail.common.base; 18993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 191bdbfefe4b144c7b031a1d9242a0fa061a0ae6b5Scott Kennedyimport static com.google.android.mail.common.base.Preconditions.checkArgument; 201bdbfefe4b144c7b031a1d9242a0fa061a0ae6b5Scott Kennedyimport static com.google.android.mail.common.base.Preconditions.checkNotNull; 211bdbfefe4b144c7b031a1d9242a0fa061a0ae6b5Scott Kennedyimport static com.google.android.mail.common.base.Preconditions.checkState; 22993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 23993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereiraimport com.google.common.base.Joiner; 24993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 25993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereiraimport java.util.Iterator; 26993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereiraimport java.util.NoSuchElementException; 27993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereiraimport java.util.StringTokenizer; 28993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereiraimport java.util.regex.Matcher; 29993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereiraimport java.util.regex.Pattern; 30993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereiraimport java.util.regex.PatternSyntaxException; 31993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 32993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira/** 33993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * An object that divides strings (or other instances of {@code CharSequence}) 34993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * into substrings, by recognizing a <i>separator</i> (a.k.a. "delimiter") 35993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * which can be expressed as a single character, literal string, regular 36993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * expression, {@code CharMatcher}, or by using a fixed substring length. This 37993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * class provides the complementary functionality to {@link Joiner}. 38993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 39993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * <p>Here is the most basic example of {@code Splitter} usage: <pre> {@code 40993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 41993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Splitter.on(',').split("foo,bar")}</pre> 42993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 43993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * This invocation returns an {@code Iterable<String>} containing {@code "foo"} 44993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * and {@code "bar"}, in that order. 45993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 46993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * <p>By default {@code Splitter}'s behavior is very simplistic: <pre> {@code 47993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 48993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Splitter.on(',').split("foo,,bar, quux")}</pre> 49993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 50993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * This returns an iterable containing {@code ["foo", "", "bar", " quux"]}. 51993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Notice that the splitter does not assume that you want empty strings removed, 52993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * or that you wish to trim whitespace. If you want features like these, simply 53993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * ask for them: <pre> {@code 54993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 55993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * private static final Splitter MY_SPLITTER = Splitter.on(',') 56993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * .trimResults() 57993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * .omitEmptyStrings();}</pre> 58993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 59993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Now {@code MY_SPLITTER.split("foo, ,bar, quux,")} returns an iterable 60993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * containing just {@code ["foo", "bar", "quux"]}. Note that the order in which 61993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * the configuration methods are called is never significant; for instance, 62993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * trimming is always applied first before checking for an empty result, 63993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * regardless of the order in which the {@link #trimResults()} and 64993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * {@link #omitEmptyStrings()} methods were invoked. 65993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 66993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * <p><b>Warning: splitter instances are always immutable</b>; a configuration 67993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * method such as {@code omitEmptyStrings} has no effect on the instance it 68993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * is invoked on! You must store and use the new splitter instance returned by 69993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * the method. This makes splitters thread-safe, and safe to store as {@code 70993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * static final} constants (as illustrated above). <pre> {@code 71993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 72993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * // Bad! Do not do this! 73993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Splitter splitter = Splitter.on('/'); 74993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * splitter.trimResults(); // does nothing! 75993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * return splitter.split("wrong / wrong / wrong");}</pre> 76993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 77993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * The separator recognized by the splitter does not have to be a single 78993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * literal character as in the examples above. See the methods {@link 79993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * #on(String)}, {@link #on(Pattern)} and {@link #on(CharMatcher)} for examples 80993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * of other ways to specify separators. 81993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 82993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * <p><b>Note:</b> this class does not mimic any of the quirky behaviors of 83993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * similar JDK methods; for instance, it does not silently discard trailing 84993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * separators, as does {@link String#split(String)}, nor does it have a default 85993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * behavior of using five particular whitespace characters as separators, like 86993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * {@link StringTokenizer}. 87993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 88993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @author Julien Silland 89993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @author Jesse Wilson 90993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @author Kevin Bourrillion 91993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @since 2009.09.15 <b>tentative</b> 92993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 93993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereirapublic final class Splitter { 94993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira private final CharMatcher trimmer; 95993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira private final boolean omitEmptyStrings; 96993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira private final Strategy strategy; 97993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 98993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira private Splitter(Strategy strategy) { 99993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira this(strategy, false, CharMatcher.NONE); 100993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 101993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 102993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira private Splitter(Strategy strategy, boolean omitEmptyStrings, 103993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira CharMatcher trimmer) { 104993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira this.strategy = strategy; 105993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira this.omitEmptyStrings = omitEmptyStrings; 106993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira this.trimmer = trimmer; 107993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 108993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 109993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /** 110993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Returns a splitter that uses the given single-character separator. For 111993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * example, {@code Splitter.on(',').split("foo,,bar")} returns an iterable 112993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * containing {@code ["foo", "", "bar"]}. 113993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 114993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param separator the character to recognize as a separator 115993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @return a splitter, with default settings, that recognizes that separator 116993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 117993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira public static Splitter on(char separator) { 118993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return on(CharMatcher.is(separator)); 119993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 120993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 121993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /** 122993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Returns a splitter that considers any single character matched by the 123993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * given {@code CharMatcher} to be a separator. For example, {@code 124993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Splitter.on(CharMatcher.anyOf(";,")).split("foo,;bar,quux")} returns an 125993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * iterable containing {@code ["foo", "", "bar", "quux"]}. 126993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 127993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param separatorMatcher a {@link CharMatcher} that determines whether a 128993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * character is a separator 129993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @return a splitter, with default settings, that uses this matcher 130993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 131993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira public static Splitter on(final CharMatcher separatorMatcher) { 132993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira checkNotNull(separatorMatcher); 133993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 134993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return new Splitter(new Strategy() { 135993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /*@Override*/ public SplittingIterator iterator( 136993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira Splitter splitter, final CharSequence toSplit) { 137993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return new SplittingIterator(splitter, toSplit) { 138993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira @Override int separatorStart(int start) { 139993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return separatorMatcher.indexIn(toSplit, start); 140993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 141993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 142993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira @Override int separatorEnd(int separatorPosition) { 143993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return separatorPosition + 1; 144993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 145993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira }; 146993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 147993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira }); 148993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 149993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 150993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /** 151993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Returns a splitter that uses the given fixed string as a separator. For 152993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * example, {@code Splitter.on(", ").split("foo, bar, baz,qux")} returns an 153993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * iterable containing {@code ["foo", "bar", "baz,qux"]}. 154993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 155993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param separator the literal, nonempty string to recognize as a separator 156993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @return a splitter, with default settings, that recognizes that separator 157993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 158993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira public static Splitter on(final String separator) { 159993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira checkArgument(separator.length() != 0, 160993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira "The separator may not be the empty string."); 161993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 162993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return new Splitter(new Strategy() { 163993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /*@Override*/ public SplittingIterator iterator( 164993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira Splitter splitter, CharSequence toSplit) { 165993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return new SplittingIterator(splitter, toSplit) { 166993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira @Override public int separatorStart(int start) { 167993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira int delimeterLength = separator.length(); 168993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 169993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira positions: 170993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira for (int p = start, last = toSplit.length() - delimeterLength; 171993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira p <= last; p++) { 172993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira for (int i = 0; i < delimeterLength; i++) { 173993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira if (toSplit.charAt(i + p) != separator.charAt(i)) { 174993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira continue positions; 175993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 176993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 177993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return p; 178993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 179993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return -1; 180993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 181993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 182993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira @Override public int separatorEnd(int separatorPosition) { 183993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return separatorPosition + separator.length(); 184993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 185993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira }; 186993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 187993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira }); 188993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 189993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 190993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /** 191993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Returns a splitter that considers any subsequence matching {@code 192993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * pattern} to be a separator. For example, {@code 193993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Splitter.on(Pattern.compile("\r?\n")).split(entireFile)} splits a string 194993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * into lines whether it uses DOS-style or UNIX-style line terminators. 195993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 196993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param separatorPattern the pattern that determines whether a subsequence 197993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * is a separator. This pattern may not match the empty string. 198993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @return a splitter, with default settings, that uses this pattern 199993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @throws IllegalArgumentException if {@code separatorPattern} matches the 200993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * empty string 201993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 202993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira public static Splitter on(final Pattern separatorPattern) { 203993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira checkNotNull(separatorPattern); 204993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira checkArgument(!separatorPattern.matcher("").matches(), 205993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira "The pattern may not match the empty string: %s", separatorPattern); 206993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 207993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return new Splitter(new Strategy() { 208993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /*@Override*/ public SplittingIterator iterator( 209993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira final Splitter splitter, CharSequence toSplit) { 210993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira final Matcher matcher = separatorPattern.matcher(toSplit); 211993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return new SplittingIterator(splitter, toSplit) { 212993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira @Override public int separatorStart(int start) { 213993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return matcher.find(start) ? matcher.start() : -1; 214993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 215993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 216993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira @Override public int separatorEnd(int separatorPosition) { 217993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return matcher.end(); 218993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 219993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira }; 220993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 221993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira }); 222993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 223993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 224993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /** 225993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Returns a splitter that considers any subsequence matching a given 226993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * pattern (regular expression) to be a separator. For example, {@code 227993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Splitter.onPattern("\r?\n").split(entireFile)} splits a string into lines 228993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * whether it uses DOS-style or UNIX-style line terminators. This is 229993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * equivalent to {@code Splitter.on(Pattern.compile(pattern))}. 230993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 231993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param separatorPattern the pattern that determines whether a subsequence 232993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * is a separator. This pattern may not match the empty string. 233993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @return a splitter, with default settings, that uses this pattern 234993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @throws PatternSyntaxException if {@code separatorPattern} is a malformed 235993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * expression 236993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @throws IllegalArgumentException if {@code separatorPattern} matches the 237993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * empty string 238993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 239993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira public static Splitter onPattern(String separatorPattern) { 240993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return on(Pattern.compile(separatorPattern)); 241993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 242993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 243993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /** 244993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Returns a splitter that divides strings into pieces of the given length. 245993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * For example, {@code Splitter.atEach(2).split("abcde")} returns an 246993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * iterable containing {@code ["ab", "cd", "e"]}. The last piece can be 247993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * smaller than {@code length} but will never be empty. 248993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 249993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param length the desired length of pieces after splitting 250993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @return a splitter, with default settings, that can split into fixed sized 251993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * pieces 252993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 253993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira public static Splitter fixedLength(final int length) { 254993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira checkArgument(length > 0, "The length may not be less than 1"); 255993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 256993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return new Splitter(new Strategy() { 257993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /*@Override*/ public SplittingIterator iterator( 258993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira final Splitter splitter, CharSequence toSplit) { 259993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return new SplittingIterator(splitter, toSplit) { 260993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira @Override public int separatorStart(int start) { 261993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira int nextChunkStart = start + length; 262993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return (nextChunkStart < toSplit.length() ? nextChunkStart : -1); 263993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 264993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 265993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira @Override public int separatorEnd(int separatorPosition) { 266993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return separatorPosition; 267993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 268993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira }; 269993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 270993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira }); 271993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 272993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 273993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /** 274993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Returns a splitter that behaves equivalently to {@code this} splitter, but 275993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * automatically omits empty strings from the results. For example, {@code 276993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Splitter.on(',').omitEmptyStrings().split(",a,,,b,c,,")} returns an 277993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * iterable containing only {@code ["a", "b", "c"]}. 278993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 279993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * <p>If either {@code trimResults} option is also specified when creating a 280993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * splitter, that splitter always trims results first before checking for 281993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * emptiness. So, for example, {@code 282993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Splitter.on(':').omitEmptyStrings().trimResults().split(": : : ")} returns 283993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * an empty iterable. 284993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 285993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * <p>Note that it is ordinarily not possible for {@link #split(CharSequence)} 286993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * to return an empty iterable, but when using this option, it can (if the 287993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * input sequence consists of nothing but separators). 288993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 289993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @return a splitter with the desired configuration 290993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 291993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira public Splitter omitEmptyStrings() { 292993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return new Splitter(strategy, true, trimmer); 293993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 294993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 295993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /** 296993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Returns a splitter that behaves equivalently to {@code this} splitter, but 297993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * automatically removes leading and trailing {@linkplain 298993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * CharMatcher#WHITESPACE whitespace} from each returned substring; equivalent 299993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * to {@code trimResults(CharMatcher.WHITESPACE)}. For example, {@code 300993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Splitter.on(',').trimResults().split(" a, b ,c ")} returns an iterable 301993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * containing {@code ["a", "b", "c"]}. 302993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 303993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @return a splitter with the desired configuration 304993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 305993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira public Splitter trimResults() { 306993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return trimResults(CharMatcher.WHITESPACE); 307993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 308993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 309993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /** 310993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Returns a splitter that behaves equivalently to {@code this} splitter, but 311993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * removes all leading or trailing characters matching the given {@code 312993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * CharMatcher} from each returned substring. For example, {@code 313993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Splitter.on(',').trimResults(CharMatcher.is('_')).split("_a ,_b_ ,c__")} 314993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * returns an iterable containing {@code ["a ", "b_ ", "c"]}. 315993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 316993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param trimmer a {@link CharMatcher} that determines whether a character 317993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * should be removed from the beginning/end of a subsequence 318993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @return a splitter with the desired configuration 319993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 320993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira public Splitter trimResults(CharMatcher trimmer) { 321993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira checkNotNull(trimmer); 322993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return new Splitter(strategy, omitEmptyStrings, trimmer); 323993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 324993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 325993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /** 326993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Splits the {@link CharSequence} passed in parameter. 327993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 328993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param sequence the sequence of characters to split 329993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @return an iteration over the segments split from the parameter. 330993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 331993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira public Iterable<String> split(final CharSequence sequence) { 332993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira checkNotNull(sequence); 333993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 334993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return new Iterable<String>() { 335993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /*@Override*/ public Iterator<String> iterator() { 336993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return strategy.iterator(Splitter.this, sequence); 337993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 338993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira }; 339993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 340993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 341993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira private interface Strategy { 342993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira Iterator<String> iterator(Splitter splitter, CharSequence toSplit); 343993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 344993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 345993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira private abstract static class SplittingIterator 346993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira extends AbstractIterator<String> { 347993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira final CharSequence toSplit; 348993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira final CharMatcher trimmer; 349993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira final boolean omitEmptyStrings; 350993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 351993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /** 352993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Returns the first index in {@code toSplit} at or after {@code start} 353993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * that contains the separator. 354993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 355993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira abstract int separatorStart(int start); 356993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 357993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /** 358993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Returns the first index in {@code toSplit} after {@code 359993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * separatorPosition} that does not contain a separator. This method is only 360993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * invoked after a call to {@code separatorStart}. 361993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 362993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira abstract int separatorEnd(int separatorPosition); 363993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 364993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira int offset = 0; 365993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 366993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira protected SplittingIterator(Splitter splitter, CharSequence toSplit) { 367993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira this.trimmer = splitter.trimmer; 368993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira this.omitEmptyStrings = splitter.omitEmptyStrings; 369993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira this.toSplit = toSplit; 370993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 371993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 372993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira @Override protected String computeNext() { 373993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira while (offset != -1) { 374993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira int start = offset; 375993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira int end; 376993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 377993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira int separatorPosition = separatorStart(offset); 378993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira if (separatorPosition == -1) { 379993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira end = toSplit.length(); 380993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira offset = -1; 381993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } else { 382993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira end = separatorPosition; 383993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira offset = separatorEnd(separatorPosition); 384993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 385993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 386993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira while (start < end && trimmer.matches(toSplit.charAt(start))) { 387993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira start++; 388993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 389993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira while (end > start && trimmer.matches(toSplit.charAt(end - 1))) { 390993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira end--; 391993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 392993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 393993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira if (omitEmptyStrings && start == end) { 394993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira continue; 395993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 396993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 397993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return toSplit.subSequence(start, end).toString(); 398993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 399993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return endOfData(); 400993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 401993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 402993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 403993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /* 404993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Copied from common.collect.AbstractIterator. TODO: un-fork once these 405993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * packages have been combined into a single library. 406993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 407993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira private static abstract class AbstractIterator<T> implements Iterator<T> { 408993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira State state = State.NOT_READY; 409993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 410993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira enum State { 411993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira READY, NOT_READY, DONE, FAILED, 412993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 413993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 414993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira T next; 415993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 416993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira protected abstract T computeNext(); 417993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 418993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira protected final T endOfData() { 419993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira state = State.DONE; 420993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return null; 421993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 422993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 423993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira public final boolean hasNext() { 424993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira checkState(state != State.FAILED); 425993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira switch (state) { 426993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira case DONE: 427993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return false; 428993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira case READY: 429993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return true; 430993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira default: 431993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 432993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return tryToComputeNext(); 433993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 434993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 435993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira boolean tryToComputeNext() { 436993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira state = State.FAILED; // temporary pessimism 437993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira next = computeNext(); 438993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira if (state != State.DONE) { 439993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira state = State.READY; 440993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return true; 441993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 442993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return false; 443993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 444993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 445993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira public final T next() { 446993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira if (!hasNext()) { 447993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira throw new NoSuchElementException(); 448993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 449993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira state = State.NOT_READY; 450993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return next; 451993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 452993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 453993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /*@Override*/ public void remove() { 454993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira throw new UnsupportedOperationException(); 455993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 456993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 457993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira} 458