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) 2006-2011 Pentaho 008// All Rights Reserved. 009*/ 010package mondrian.util; 011 012import mondrian.olap.Util; 013 014import java.lang.reflect.Array; 015import java.util.*; 016 017/** 018 * Implementation of {@link java.util.List} for transposing an array of 019 * lists. 020 * 021 * @author Luis F. Canals 022 * @since Dec, 2007 023 */ 024public class TraversalList<T> extends UnsupportedList<List<T>> { 025 private boolean asInternalArray = false; 026 private List<T>[] internalArray = null; 027 private final List<T>[] lists; 028 private final Class<T> clazz; 029 private final T[] tmpArray; // work space; not threadsafe even for reads 030 031 public TraversalList( 032 final List<T>[] lists, 033 Class<T> clazz) 034 { 035 this.lists = lists; 036 this.clazz = clazz; 037 //noinspection unchecked 038 this.tmpArray = (T[]) Array.newInstance(clazz, lists.length); 039 } 040 041 public List<T> get(int index) { 042 if (this.asInternalArray) { 043 return internalArray[index]; 044 } else { 045 for (int i = 0; i < lists.length; i++) { 046 tmpArray[i] = lists[i].get(index); 047 } 048 return Util.flatList(tmpArray.clone()); 049 } 050 } 051 052 public Iterator<List<T>> iterator() { 053 return new Iterator<List<T>>() { 054 private int currentIndex = 0; 055 private List<T> precalculated; 056 057 public List<T> next() { 058 if (precalculated != null) { 059 final List<T> t = precalculated; 060 precalculated = null; 061 currentIndex++; 062 return t; 063 } else { 064 return get(currentIndex++); 065 } 066 } 067 068 public boolean hasNext() { 069 try { 070 precalculated = get(currentIndex); 071 return true; 072 } catch (IndexOutOfBoundsException e) { 073 return false; 074 } 075 } 076 077 public void remove() { 078 throw new UnsupportedOperationException(); 079 } 080 }; 081 } 082 083 // Used by Collections.sort 084 public ListIterator<List<T>> listIterator(final int index) { 085 return new ListItr(index) { 086 public void set(final List<T> l) { 087 TraversalList.this.set(cursor - 1, l); 088 } 089 }; 090 } 091 092 // Used by Collections.sort 093 public ListIterator<List<T>> listIterator() { 094 return new ListItr(0) { 095 public void set(final List<T> l) { 096 TraversalList.this.set(cursor - 1, l); 097 } 098 }; 099 } 100 101 public int size() { 102 return lists[0].size(); 103 } 104 105 public List<List<T>> subList(final int first, final int last) { 106 return new AbstractList<List<T>>() { 107 public List<T> get(int index) { 108 return TraversalList.this.get(index + first); 109 } 110 public int size() { 111 return last - first; 112 } 113 }; 114 } 115 116 private List<T>[] materialize(List<T>[] a) { 117 final List<T>[] array; 118 if (a != null 119 && a.length == size() 120 && a.getClass().getComponentType() == clazz) 121 { 122 array = a; 123 } else { 124 //noinspection unchecked 125 array = (List<T>[]) new List[this.size()]; 126 } 127 int k = 0; 128 for (List<T> x : this) { 129 array[k++] = x; 130 } 131 this.asInternalArray = true; 132 this.internalArray = array; 133 return array; 134 } 135 136 @Override 137 public <S> S[] toArray(S[] a) { 138 // Our requirements are stronger than the general toArray(T[] a) 139 // contract. We will use the user's array 'a' only if it is PRECISELY 140 // the right type and size; otherwise we will allocate our own array. 141 //noinspection unchecked 142 return (S[]) materialize((List<T>[]) a); 143 } 144 145 public Object[] toArray() { 146 return materialize(null); 147 } 148 149 // Used by Collections.sort 150 public List<T> set(final int index, List<T> l) { 151 if (this.asInternalArray) { 152 final List<T> previous = this.internalArray[index]; 153 this.internalArray[index] = l; 154 return previous; 155 } else { 156 throw new UnsupportedOperationException(); 157 } 158 } 159} 160 161// End TraversalList.java