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) 2011-2011 Pentaho
008// All Rights Reserved.
009*/
010package mondrian.calc.impl;
011
012import mondrian.calc.*;
013import mondrian.olap.Evaluator;
014import mondrian.olap.Member;
015
016import java.util.*;
017
018/**
019 * Abstract implementation of {@link TupleList}.
020 *
021 * @author jhyde
022 */
023public abstract class AbstractTupleList
024    extends AbstractList<List<Member>>
025    implements RandomAccess, Cloneable, TupleList
026{
027    protected final int arity;
028    protected boolean mutable = true;
029
030    public AbstractTupleList(int arity) {
031        this.arity = arity;
032    }
033
034    public int getArity() {
035        return arity;
036    }
037
038    protected abstract TupleIterator tupleIteratorInternal();
039
040    @Override
041    public abstract TupleList subList(int fromIndex, int toIndex);
042
043    public TupleList fix() {
044        return new DelegatingTupleList(
045            arity,
046            new ArrayList<List<Member>>(this));
047    }
048
049    @Override
050    public final Iterator<List<Member>> iterator() {
051        return tupleIteratorInternal();
052    }
053
054    public final TupleIterator tupleIterator() {
055        return tupleIteratorInternal();
056    }
057
058    /**
059     * Creates a {@link TupleCursor} over this list.
060     *
061     * <p>Any implementation of {@link TupleList} must implement all three
062     * methods {@link #iterator()}, {@link #tupleIterator()} and
063     * {@code tupleCursor}. The default implementation returns the same
064     * for all three, but a derived classes can override this method to create a
065     * more efficient implementation that implements cursor but not iterator.
066     *
067     * @return A cursor over this list
068     */
069    public TupleCursor tupleCursor() {
070        return tupleIteratorInternal();
071    }
072
073    public void addCurrent(TupleCursor tupleIter) {
074        add(tupleIter.current());
075    }
076
077    public Member get(int slice, int index) {
078        return get(index).get(slice);
079    }
080
081    /**
082     * Implementation of {@link mondrian.calc.TupleIterator} for
083     * {@link ArrayTupleList}.
084     * Based upon AbstractList.Itr, but with concurrent modification checking
085     * removed.
086     */
087    protected class AbstractTupleListIterator
088        implements TupleIterator
089    {
090        /**
091         * Index of element to be returned by subsequent call to next.
092         */
093        int cursor = 0;
094
095        /**
096         * Index of element returned by most recent call to next or
097         * previous.  Reset to -1 if this element is deleted by a call
098         * to remove.
099         */
100        int lastRet = -1;
101
102        public boolean hasNext() {
103            return cursor != size();
104        }
105
106        public List<Member> next() {
107            try {
108                List<Member> next = get(cursor);
109                lastRet = cursor++;
110                return next;
111            } catch (IndexOutOfBoundsException e) {
112                throw new NoSuchElementException();
113            }
114        }
115
116        public boolean forward() {
117            if (cursor == size()) {
118                return false;
119            }
120            lastRet = cursor++;
121            return true;
122        }
123
124        public List<Member> current() {
125            return get(lastRet);
126        }
127
128        public void currentToArray(Member[] members, int offset) {
129            final List<Member> current = current();
130            if (offset == 0) {
131                current.toArray(members);
132            } else {
133                //noinspection SuspiciousSystemArraycopy
134                System.arraycopy(current.toArray(), 0, members, offset, arity);
135            }
136        }
137
138        public int getArity() {
139            return AbstractTupleList.this.getArity();
140        }
141
142        public void remove() {
143            assert mutable;
144            if (lastRet == -1) {
145                throw new IllegalStateException();
146            }
147            try {
148                AbstractTupleList.this.remove(lastRet);
149                if (lastRet < cursor) {
150                    cursor--;
151                }
152                lastRet = -1;
153            } catch (IndexOutOfBoundsException e) {
154                throw new ConcurrentModificationException();
155            }
156        }
157
158        public void setContext(Evaluator evaluator) {
159            evaluator.setContext(current());
160        }
161
162        public Member member(int column) {
163            return get(lastRet).get(column);
164        }
165    }
166}
167
168// End AbstractTupleList.java