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