001 /* 002 // $Id: //open/mondrian/src/main/mondrian/util/FilteredIterableList.java#3 $ 003 // This software is subject to the terms of the Common Public License 004 // Agreement, available at the following URL: 005 // http://www.opensource.org/licenses/cpl.html. 006 // Copyright (C) 2006-2008 Julian Hyde 007 // All Rights Reserved. 008 // You must accept the terms of that agreement to use this software. 009 */ 010 package mondrian.util; 011 012 import java.util.*; 013 014 /** 015 * Iterable list which filters undesirable elements. 016 * To be used instead of removing elements from an iterable list. 017 * 018 * @author Luis F. Canals 019 * @version $Id: //open/mondrian/src/main/mondrian/util/FilteredIterableList.java#3 $ 020 * @since december, 2007 021 */ 022 public class FilteredIterableList<T> extends AbstractSequentialList<T> { 023 private List<T> plainList; 024 private int size; 025 private boolean isEmpty; 026 private int lastIndex = 0; 027 private int lastGetIndex = -1; 028 private T lastGet = null; 029 private ListIterator<T> lastListIterator; 030 031 private final List<? extends T> internal; 032 private final Filter<T> filter; 033 034 private final Map<Integer, T> cached; 035 036 public FilteredIterableList(final List<? extends T> list, 037 final Filter filter) { 038 super(); 039 this.plainList = null; 040 this.filter = filter; 041 this.internal = list; 042 this.isEmpty = ! this.listIterator(0).hasNext(); 043 this.size = -1; 044 this.cached = new CacheMap<Integer, T>(4); 045 } 046 047 public T get(final int index) { 048 if (this.plainList != null) { 049 return this.plainList.get(index); 050 } 051 052 final T t = cached.get(index); 053 if (t != null) { 054 return cached.get(index); 055 } else { 056 if (index != this.lastGetIndex || index < 0) { 057 this.lastGet = super.get(index); 058 if (this.lastGet == null) { 059 throw new IndexOutOfBoundsException(); 060 } 061 this.lastGetIndex = index; 062 } 063 cached.put(index, this.lastGet); 064 return this.lastGet; 065 } 066 } 067 068 public ListIterator<T> listIterator(final int index) { 069 if (this.plainList == null) { 070 if (index == this.lastIndex + 1 && this.lastListIterator != null) { 071 if (this.lastListIterator.hasNext()) { 072 this.lastIndex = index; 073 return this.lastListIterator; 074 } else { 075 throw new IndexOutOfBoundsException(); 076 } 077 } else { 078 final Iterator<? extends T> it = internal.iterator(); 079 T nextTmp = null; 080 while (it.hasNext()) { 081 final T n = it.next(); 082 if (filter.accept(n)) { 083 nextTmp = n; 084 break; 085 } 086 } 087 final T first = nextTmp; 088 this.lastListIterator = new ListIterator<T>() { 089 private int idx = 0; 090 private T nxt = first; 091 private void postNext() { 092 while (it.hasNext()) { 093 final T n = it.next(); 094 if (filter.accept(n)) { 095 nxt = n; 096 return; 097 } 098 } 099 nxt = null; 100 } 101 public boolean hasNext() { 102 return nxt != null; 103 } 104 public T next() { 105 idx++; 106 final T n = nxt; 107 cached.put(idx - 1, n); 108 postNext(); 109 return n; 110 } 111 public int nextIndex() { 112 return idx; 113 } 114 public void add(final T t) { 115 throw new UnsupportedOperationException(); 116 } 117 public void set(final T t) { 118 throw new UnsupportedOperationException(); 119 } 120 public boolean hasPrevious() { 121 throw new UnsupportedOperationException(); 122 } 123 public T previous() { 124 throw new UnsupportedOperationException(); 125 } 126 public int previousIndex() { 127 throw new UnsupportedOperationException(); 128 } 129 public void remove() { 130 throw new UnsupportedOperationException(); 131 } 132 }; 133 this.lastIndex = 0; 134 } 135 136 for (int i = this.lastIndex; i < index; i++) { 137 if (!this.lastListIterator.hasNext()) { 138 throw new IndexOutOfBoundsException(); 139 } 140 this.lastListIterator.next(); 141 } 142 this.lastIndex = index; 143 return this.lastListIterator; 144 } else { 145 return plainList.listIterator(index); 146 } 147 } 148 149 public boolean isEmpty() { 150 return this.plainList != null ? this.plainList.isEmpty() : this.isEmpty; 151 } 152 153 public int size() { 154 if (this.size == -1) { 155 int s = this.lastIndex; 156 try { 157 final ListIterator<T> it = this.listIterator(this.lastIndex); 158 while (it.hasNext()) { 159 s++; 160 it.next(); 161 } 162 } catch (IndexOutOfBoundsException ioobe) { 163 // Subyacent list is no more present... 164 } 165 this.size = s; 166 } 167 this.lastListIterator = null; 168 return this.size; 169 } 170 171 public Object[] toArray() { 172 if (this.plainList == null) { 173 final List<T> tmpPlainList = new ArrayList<T>(); 174 int size = 0; 175 for (final Iterator<T> it = this.listIterator(0); it.hasNext();) { 176 tmpPlainList.add(it.next()); 177 size++; 178 } 179 this.plainList = tmpPlainList; 180 } 181 return this.plainList.toArray(); 182 } 183 184 public int hashCode() { 185 return this.filter.hashCode(); 186 } 187 188 /* 189 public List<T> subList(final int start, final int end) { 190 return new AbstractList<T>() { 191 public T get(final int index) { 192 return FilteredIterableList.this.get(index-start); 193 } 194 public int size() { 195 return FilteredIterableList.this.size() - start; 196 } 197 }; 198 } 199 */ 200 201 202 // 203 // Inner classes --------------------------------- 204 // 205 206 /** 207 * Filter to determine which elements should be shown. 208 */ 209 public static interface Filter<T> { 210 public boolean accept(final T element); 211 } 212 } 213 214 // End FilteredIterableList.java