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