001 /* 002 // $Id: //open/mondrian/src/main/mondrian/util/ConcatenableList.java#5 $ 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 * @author Luis F. Canals 016 * @version $Id: //open/mondrian/src/main/mondrian/util/ConcatenableList.java#5 $ 017 * @since december, 2007 018 */ 019 public class ConcatenableList<T> extends AbstractList<T> { 020 private static int nextHashCode = 1000; 021 private final List<List<T>> lists; 022 private List<T> plainList; 023 private final int hashCode = nextHashCode++; 024 private Iterator<T> getIterator = null; 025 private int previousIndex = -200; 026 private T previousElement = null; 027 private T prePreviousElement = null; 028 029 public ConcatenableList() { 030 this.lists = new ArrayList<List<T>>(); 031 this.plainList = null; 032 } 033 034 035 /** 036 * Performs a load of all elements into memory, removing sequential 037 * access advantages. 038 */ 039 public Object[] toArray() { 040 if (this.plainList == null) { 041 this.plainList = new ArrayList<T>(); 042 for (final List<T> list : lists) { 043 for (final T t : list) { 044 this.plainList.add(t); 045 } 046 } 047 } 048 return this.plainList.toArray(); 049 } 050 051 public boolean addAll(final Collection<? extends T> collection) { 052 if (this.plainList == null) { 053 final List<T> list = (List<T>) collection; 054 return this.lists.add(list); 055 } else { 056 for (final T e : collection) { 057 this.plainList.add(e); 058 } 059 return true; 060 } 061 } 062 063 public T get(final int index) { 064 if (this.plainList == null) { 065 if (index == 0) { 066 this.getIterator = this.iterator(); 067 this.previousIndex = index; 068 if (this.getIterator.hasNext()) { 069 this.previousElement = this.getIterator.next(); 070 return this.previousElement; 071 } else { 072 this.getIterator = null; 073 this.previousIndex = -200; 074 throw new IndexOutOfBoundsException("Index " + index 075 + " out of concatenable list range"); 076 } 077 } else if (this.previousIndex + 1 == index && this.getIterator != null) { 078 this.previousIndex = index; 079 if (this.getIterator.hasNext()) { 080 this.prePreviousElement = this.previousElement; 081 this.previousElement = this.getIterator.next(); 082 return this.previousElement; 083 } else { 084 this.getIterator = null; 085 this.previousIndex = -200; 086 throw new IndexOutOfBoundsException("Index " + index 087 + " out of concatenable list range"); 088 } 089 } else if (this.previousIndex == index) { 090 return this.previousElement; 091 } else if (this.previousIndex - 1 == index) { 092 return this.prePreviousElement; 093 } else { 094 this.previousIndex = -200; 095 this.getIterator = null; 096 final Iterator<T> it = this.iterator(); 097 if (!it.hasNext()) { 098 throw new IndexOutOfBoundsException("Index " + index 099 + " out of concatenable list range"); 100 } 101 for (int i = 0; i < index; i++) { 102 if (!it.hasNext()) { 103 throw new IndexOutOfBoundsException("Index " + index 104 + " out of concatenable list range"); 105 } 106 this.prePreviousElement = it.next(); 107 } 108 this.previousElement = it.next(); 109 this.previousIndex = index; 110 this.getIterator = it; 111 return this.previousElement; 112 } 113 } else { 114 this.previousElement = this.plainList.get(index); 115 return this.previousElement; 116 } 117 } 118 119 120 /** 121 * Adds elements at the end of the list. 122 */ 123 public boolean add(final T t) { 124 if (this.plainList == null) { 125 return this.addAll(Collections.singletonList(t)); 126 } else { 127 return this.plainList.add(t); 128 } 129 } 130 131 /** 132 * Adds elements at the middle of the list. 133 */ 134 public void add(final int index, final T t) { 135 if (this.plainList == null) { 136 throw new UnsupportedOperationException(); 137 } else { 138 this.plainList.add(index, t); 139 } 140 } 141 142 143 144 /** 145 * Burnt method! 146 */ 147 public T set(final int index, final T t) { 148 if (this.plainList == null) { 149 throw new UnsupportedOperationException(); 150 } else { 151 return this.plainList.set(index, t); 152 } 153 } 154 155 public int size() { 156 if (this.plainList == null) { 157 int size = 0; 158 for (final List<T> list : lists) { 159 size += list.size(); 160 } 161 return size; 162 } else { 163 return this.plainList.size(); 164 } 165 } 166 167 public Iterator<T> iterator() { 168 if (this.plainList == null) { 169 return new Iterator<T>() { 170 private final Iterator<List<T>> listsIt=lists.iterator(); 171 private Iterator<T> currentListIt; 172 173 public boolean hasNext() { 174 if (currentListIt == null) { 175 if (listsIt.hasNext()) { 176 currentListIt = listsIt.next().iterator(); 177 } else { 178 return false; 179 } 180 } 181 182 if (currentListIt.hasNext()) { 183 return true; 184 } else { 185 if (listsIt.hasNext()) { 186 currentListIt = listsIt.next().iterator(); 187 return currentListIt.hasNext(); 188 } else { 189 return false; 190 } 191 } 192 } 193 194 public T next() { 195 if (currentListIt.hasNext()) { 196 return currentListIt.next(); 197 } else { 198 currentListIt = listsIt.next().iterator(); 199 return currentListIt.next(); 200 } 201 } 202 203 public void remove() { 204 throw new UnsupportedOperationException(); 205 } 206 }; 207 } else { 208 return this.plainList.iterator(); 209 } 210 } 211 212 public boolean isEmpty() { 213 if (this.plainList != null) { 214 return this.plainList.isEmpty(); 215 } 216 if (this.lists.isEmpty()) { 217 return true; 218 } else { 219 for (final List<T> l : lists) { 220 if (!l.isEmpty()) { 221 return false; 222 } 223 } 224 return true; 225 } 226 } 227 228 public void clear() { 229 this.plainList = null; 230 this.lists.clear(); 231 } 232 233 public int hashCode() { 234 return this.hashCode; 235 } 236 } 237 238 // End ConcatenableList.java