001/* 002// This software is subject to the terms of the Eclipse Public License v1.0 003// Agreement, available at the following URL: 004// http://www.eclipse.org/legal/epl-v10.html. 005// You must accept the terms of that agreement to use this software. 006// 007// Copyright (C) 2008-2009 Pentaho 008// All Rights Reserved. 009*/ 010package mondrian.util; 011 012import mondrian.olap.Util; 013 014import java.util.*; 015 016/** 017 * Iterator over union of several {@link Iterable} collections. 018 * 019 * <p>Try, for instance, using the {@link #over} helper method:</p> 020 * 021 * <blockquote> 022 * <code> 023 * List<String> names;<br/> 024 * List<String> addresses;<br/> 025 * for (Sstring s : UnionIterator.over(names, addresses)) { 026 * print(s);<br/> 027 * } 028 * </code> 029 * </blockquote> 030 * 031 * @author jhyde 032 * @since Apr 28, 2008 033 */ 034public class UnionIterator<T> implements Iterator<T> { 035 private final Iterator<Iterable<? extends T>> iterableIterator; 036 private Iterator<? extends T> iterator; 037 038 /** 039 * Creates a UnionIterator. 040 * 041 * @param iterables Array of iterables 042 */ 043 public UnionIterator(Iterable<? extends T>... iterables) { 044 List<Iterable<? extends T>> list; 045 if (Util.Retrowoven) { 046 // Retroweaver has its own version of Iterable, but 047 // Collection doesn't implement it. Solve the problem by 048 // creating an explicit Iterable wrapper. 049 list = new ArrayList<Iterable<? extends T>>(iterables.length); 050 for (Iterable<? extends T> iterable : iterables) { 051 //noinspection unchecked 052 list.add(new MyIterable(iterable)); 053 } 054 } else { 055 list = Arrays.asList(iterables); 056 } 057 this.iterableIterator = list.iterator(); 058 moveToNext(); 059 } 060 061 /** 062 * Creates a UnionIterator over a list of collections. 063 * 064 * @param iterables Array of collections 065 */ 066 public UnionIterator(Collection<? extends T>... iterables) { 067 List<Iterable<? extends T>> list = 068 new ArrayList<Iterable<? extends T>>(iterables.length); 069 for (Iterable<? extends T> iterable : iterables) { 070 //noinspection unchecked 071 list.add(new MyIterable(iterable)); 072 } 073 this.iterableIterator = list.iterator(); 074 moveToNext(); 075 } 076 077 public boolean hasNext() { 078 return iterator.hasNext(); 079 } 080 081 public T next() { 082 final T t = iterator.next(); 083 if (!iterator.hasNext()) { 084 moveToNext(); 085 } 086 return t; 087 } 088 089 /** 090 * Moves to the next iterator that has at least one element. 091 * Called after finishing an iterator, or at the start. 092 */ 093 private void moveToNext() { 094 do { 095 if (iterableIterator.hasNext()) { 096 iterator = iterableIterator.next().iterator(); 097 } else { 098 iterator = Collections.<T>emptyList().iterator(); 099 break; 100 } 101 } while (!iterator.hasNext()); 102 } 103 104 public void remove() { 105 iterator.remove(); 106 } 107 108 /** 109 * Returns the union of a list of iterables. 110 * 111 * <p>You can use it like this: 112 * <blockquote><pre> 113 * Iterable<String> iter1; 114 * Iterable<String> iter2; 115 * for (String s : union(iter1, iter2)) { 116 * print(s); 117 * }</pre></blockquote> 118 * 119 * @param iterables Array of one or more iterables 120 * @return iterable over the union of the iterables 121 */ 122 public static <T> Iterable<T> over( 123 final Iterable<? extends T>... iterables) 124 { 125 return new Iterable<T>() { 126 public Iterator<T> iterator() { 127 return new UnionIterator<T>(iterables); 128 } 129 }; 130 } 131 132 /** 133 * Returns the union of a list of collections. 134 * 135 * <p>This method exists for code that will be retrowoven to run on JDK 1.4. 136 * Retroweaver has its own version of the {@link Iterable} interface, which 137 * is problematic since the {@link java.util.Collection} classes don't 138 * implement it. This method solves some of these problems by working in 139 * terms of collections; retroweaver deals with these correctly. 140 * 141 * @see #over(Iterable[]) 142 * 143 * @param collections Array of one or more collections 144 * @return iterable over the union of the collections 145 */ 146 public static <T> Iterable<T> over( 147 final Collection<? extends T>... collections) 148 { 149 return new Iterable<T>() { 150 public Iterator<T> iterator() { 151 return new UnionIterator<T>(collections); 152 } 153 }; 154 } 155 156 private static class MyIterable<T> implements Iterable { 157 private final Iterable<T> iterable; 158 159 /** 160 * Creates a MyIterable. 161 * 162 * @param iterable Iterable 163 */ 164 public MyIterable(Iterable<T> iterable) { 165 this.iterable = iterable; 166 } 167 168 public Iterator<T> iterator() { 169 return iterable.iterator(); 170 } 171 } 172} 173 174// End UnionIterator.java