1 package org.unicode.cldr.util; 2 3 import java.util.ArrayList; 4 import java.util.Arrays; 5 import java.util.Collection; 6 import java.util.Iterator; 7 import java.util.List; 8 9 import com.ibm.icu.lang.CharSequences; 10 import com.ibm.icu.text.Transform; 11 import com.ibm.icu.text.UTF16; 12 13 /** 14 * Simple cover class for converting iterators, lists of items, arrays, and 15 * CharSequences into forms usable with for loops. Example: 16 * 17 * <pre> 18 * for (String s : With.in(someIterator)) { 19 * doSomethingWith(s); 20 * } 21 * 22 * for (int codePoint : With.codePointArray("abc\uD800\uDC00")) { 23 * doSomethingWith(codePoint); 24 * } 25 * 26 * for (int integer : With.array(1, 99, 3, 42)) { 27 * doSomethingWith(integer); 28 * } 29 * </pre> 30 * 31 * @author markdavis 32 * 33 * @param <V> 34 */ 35 public final class With<V> implements Iterable<V>, Iterator<V> { 36 List<Iterator<V>> iterators = new ArrayList<Iterator<V>>(); 37 int current; 38 39 /** 40 * Interface for an iterator that is simpler to implement, without 'look-ahead'. 41 * Using With.in(), this can be transformed into a regular Java iterator. 42 * The one restriction is that elements cannot be null, since that signals end of the sequence. 43 * 44 * @author markdavis 45 * 46 * @param <T> 47 */ 48 public interface SimpleIterator<T> { 49 /** 50 * Returns null when done 51 * 52 * @return object, or null when done. 53 */ next()54 public T next(); 55 } 56 57 @Override iterator()58 public Iterator<V> iterator() { 59 return this; 60 } 61 62 @Override hasNext()63 public boolean hasNext() { 64 while (current < iterators.size()) { 65 if (iterators.get(current).hasNext()) { 66 return true; 67 } 68 current++; 69 } 70 return false; 71 } 72 73 @Override next()74 public V next() { 75 return iterators.get(current).next(); 76 } 77 78 @Override remove()79 public void remove() { 80 throw new UnsupportedOperationException(); 81 } 82 83 /** 84 * Create a collection from whatever is left in the iterator. For example, myCollection = 85 * With.in(anIterator).toList(); 86 * 87 * @return 88 */ toList()89 public List<V> toList() { 90 return toCollection(new ArrayList<V>()); 91 } 92 93 /** 94 * Create a collection from whatever is left in the iterator. For example, myCollection = 95 * With.in(anIterator).toList(); 96 * 97 * @return 98 */ toCollection(C output)99 public <C extends Collection<V>> C toCollection(C output) { 100 while (hasNext()) { 101 output.add(next()); 102 } 103 return output; 104 } 105 106 /** 107 * Create a collection from whatever is left in the iterator. For example, myCollection = 108 * With.in(anIterator).toList(); 109 * 110 * @return 111 */ toUnmodifiableCollection(C output)112 public <C extends Collection<V>> C toUnmodifiableCollection(C output) { 113 while (hasNext()) { 114 output.add(next()); 115 } 116 return CldrUtility.protectCollection(output); 117 } 118 119 /** 120 * Create a collection from whatever is left in the iterator. For example, myCollection = 121 * With.in(anIterator).toList(); 122 * 123 * @return 124 */ toCollection(Transform<V, W> filter, C output)125 public <W, C extends Collection<W>> C toCollection(Transform<V, W> filter, C output) { 126 while (hasNext()) { 127 W transformedItem = filter.transform(next()); 128 if (transformedItem != null) { 129 output.add(transformedItem); 130 } 131 } 132 return output; 133 } 134 135 /** 136 * Create an immutable collection from whatever is left in the iterator. For example, myCollection = 137 * With.in(anIterator).toList(); 138 * 139 * @return 140 */ toUnmodifiableCollection(Transform<V, W> filter, C output)141 public <W, C extends Collection<W>> C toUnmodifiableCollection(Transform<V, W> filter, C output) { 142 return CldrUtility.protectCollection(toCollection(filter, output)); 143 } 144 145 /** 146 * Create a simple object for use in for loops. Example: 147 * 148 * <pre> 149 * for (int integer : With.in(1, 99, 3, 42)) { 150 * doSomethingWith(integer); 151 * } 152 * </pre> 153 * 154 * @param <V> 155 * @param iterator 156 * @return Iterable, for use in for loops, etc. 157 */ 158 @SuppressWarnings("unchecked") array(V... values)159 public static <V> V[] array(V... values) { 160 return values; 161 } 162 163 /** 164 * Create a simple object for use in for loops, handling code points 165 * properly. Example: 166 * 167 * <pre> 168 * for (int codePoint : With.in("abc\uD800\uDC00")) { 169 * doSomethingWith(codePoint); 170 * } 171 * </pre> 172 * 173 * Actually returns an array, which avoids boxing/unboxing costs. 174 * 175 * @param iterator 176 * @return Iterable, for use in for loops, etc. 177 */ codePointArray(CharSequence source)178 public static int[] codePointArray(CharSequence source) { 179 return CharSequences.codePoints(source); 180 } 181 182 /** 183 * An alterative to With.in(CharSequence) that is better when it is likely that only a portion of the text will be 184 * looked at, 185 * such as when an iterator over codepoints is aborted partway. 186 * 187 * @param old 188 * @return 189 */ codePoints(CharSequence... charSequences)190 public static With<CharSequence> codePoints(CharSequence... charSequences) { 191 return new With<CharSequence>().andCodePoints(charSequences); 192 } 193 194 /** 195 * Create a simple object for use in for loops. Example: 196 * 197 * <pre> 198 * for (String s : With.in(someIterator)) { 199 * doSomethingWith(s); 200 * } 201 * </pre> 202 * 203 * @param <V> 204 * @param iterator 205 * @return Iterable, for use in for loops, etc. 206 */ 207 @SafeVarargs 208 @SuppressWarnings("unchecked") in(Iterator<V>.... iterators)209 public static <V> With<V> in(Iterator<V>... iterators) { 210 return new With<V>().and(iterators); 211 } 212 213 /** 214 * Create a simple object for use in for loops. Example: 215 * 216 * <pre> 217 * for (String s : With.in(someIterator)) { 218 * doSomethingWith(s); 219 * } 220 * </pre> 221 * 222 * @param <V> 223 * @param iterator 224 * @return Iterable, for use in for loops, etc. 225 */ 226 @SuppressWarnings("unchecked") in(Iterable<V>.... iterables)227 public static <V> With<V> in(Iterable<V>... iterables) { 228 return new With<V>().and(iterables); 229 } 230 231 /** 232 * Create a simple object for use in for loops. Example: 233 * 234 * <pre> 235 * for (String s : With.in(someIterator)) { 236 * doSomethingWith(s); 237 * } 238 * </pre> 239 * 240 * @param <V> 241 * @param iterator 242 * @return Iterable, for use in for loops, etc. 243 */ 244 @SuppressWarnings("unchecked") in(V... items)245 public static <V> With<V> in(V... items) { 246 return new With<V>().and(items); 247 } 248 249 /** 250 * Creates an iterable from a simple iterator. 251 * 252 * @param <T> 253 * @param old 254 * @return 255 */ 256 @SuppressWarnings("unchecked") in(SimpleIterator<T>.... sources)257 public static <T> Iterable<T> in(SimpleIterator<T>... sources) { 258 return new With<T>().and(sources); 259 } 260 With()261 private With() { 262 } 263 264 @SuppressWarnings("unchecked") and(Iterator<V>.... iterators)265 public With<V> and(Iterator<V>... iterators) { 266 for (Iterator<V> iterator : iterators) { 267 this.iterators.add(iterator); 268 } 269 return this; 270 } 271 272 @SuppressWarnings("unchecked") and(V... items)273 public With<V> and(V... items) { 274 return and(Arrays.asList(items)); 275 } 276 277 @SuppressWarnings("unchecked") and(Iterable<V>.... iterables)278 public With<V> and(Iterable<V>... iterables) { 279 for (Iterable<V> iterable : iterables) { 280 this.iterators.add(iterable.iterator()); 281 } 282 return this; 283 } 284 285 @SuppressWarnings("unchecked") and(SimpleIterator<V>.... iterators)286 public With<V> and(SimpleIterator<V>... iterators) { 287 for (SimpleIterator<V> iterator : iterators) { 288 this.iterators.add(new ToIterator<V>(iterator)); 289 } 290 return this; 291 } 292 293 /** 294 * Will fail if V is not a CharSequence. 295 * 296 * @param sources 297 * @return 298 */ andCodePoints(CharSequence... sources)299 public With<V> andCodePoints(CharSequence... sources) { 300 for (CharSequence charSequence : sources) { 301 this.iterators 302 .add((Iterator<V>) new ToIterator<CharSequence>(new CharSequenceSimpleIterator(charSequence))); 303 } 304 return this; 305 } 306 307 // new CharSequenceSimpleIterator(source) 308 309 private static class CharSequenceSimpleIterator implements SimpleIterator<CharSequence> { 310 private int position; 311 private CharSequence source; 312 CharSequenceSimpleIterator(CharSequence source)313 public CharSequenceSimpleIterator(CharSequence source) { 314 this.source = source; 315 } 316 317 @Override next()318 public CharSequence next() { 319 // TODO optimize 320 if (position >= source.length()) { 321 return null; 322 } 323 int codePoint = Character.codePointAt(source, position); 324 position += Character.charCount(codePoint); 325 return UTF16.valueOf(codePoint); 326 } 327 } 328 toIterator(SimpleIterator<T> simple)329 public static <T> Iterator<T> toIterator(SimpleIterator<T> simple) { 330 return new ToIterator<T>(simple); 331 } 332 toIterable(SimpleIterator<T> simple)333 public static <T> Iterable<T> toIterable(SimpleIterator<T> simple) { 334 return new ToIterator<T>(simple); 335 } 336 toSimpleIterator(Iterator<T> iterator)337 public static <T> ToSimpleIterator<T> toSimpleIterator(Iterator<T> iterator) { 338 return new ToSimpleIterator<T>(iterator); 339 } 340 341 private static class ToIterator<T> implements Iterator<T>, Iterable<T> { 342 private final SimpleIterator<T> simpleIterator; 343 private T current; 344 345 /** 346 * @param simpleIterator 347 */ ToIterator(SimpleIterator<T> simpleIterator)348 public ToIterator(SimpleIterator<T> simpleIterator) { 349 this.simpleIterator = simpleIterator; 350 current = simpleIterator.next(); 351 } 352 353 @Override hasNext()354 public boolean hasNext() { 355 return current != null; 356 } 357 358 @Override next()359 public T next() { 360 T result = current; 361 current = simpleIterator.next(); 362 return result; 363 } 364 365 @Override remove()366 public void remove() { 367 throw new UnsupportedOperationException(); 368 } 369 370 @Override iterator()371 public Iterator<T> iterator() { 372 return this; 373 } 374 } 375 376 private static class ToSimpleIterator<T> implements SimpleIterator<T> { 377 private final Iterator<T> iterator; 378 ToSimpleIterator(Iterator<T> iterator)379 public ToSimpleIterator(Iterator<T> iterator) { 380 this.iterator = iterator; 381 } 382 383 @Override next()384 public T next() { 385 return iterator.hasNext() ? iterator.next() : null; 386 } 387 } 388 389 } 390