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 * Implementation of {@link TupleList} where the tuples are unary (each tuple
020 * consists of just one {@link Member}).
021 *
022 * <p>It is implemented as a straightforward wrapper on a backing list. You
023 * can provide the backing list explicitly using the
024 * {@link #UnaryTupleList(java.util.List)} constructor, and you can access the
025 * backing list by calling {@link #slice}(0).
026 *
027 * @author jhyde
028*/
029public class UnaryTupleList
030    extends AbstractList<List<Member>>
031    implements TupleList
032{
033    final List<Member> list;
034
035    /**
036     * Creates an empty UnaryTupleList.
037     */
038    public UnaryTupleList() {
039        this(new ArrayList<Member>());
040    }
041
042    /**
043     * Creates a UnaryTupleList with a given backing list.
044     *
045     * @param list Backing list
046     */
047    public UnaryTupleList(List<Member> list) {
048        this.list = list;
049    }
050
051    public Member get(int slice, int index) {
052        assert slice == 0;
053        return list.get(index);
054    }
055
056    @Override
057    public List<Member> get(int index) {
058        return Collections.singletonList(list.get(index));
059    }
060
061    @Override
062    public void add(int index, List<Member> element) {
063        list.add(index, element.get(0));
064    }
065
066    @Override
067    public boolean add(List<Member> element) {
068        return list.add(element.get(0));
069    }
070
071    public TupleList fix() {
072        return this;
073    }
074
075    @Override
076    public List<Member> set(int index, List<Member> element) {
077        final Member member = list.set(index, element.get(0));
078        return member == null
079            ? null
080            : Collections.singletonList(member);
081    }
082
083    @Override
084    public List<Member> remove(int index) {
085        final Member member = list.remove(index);
086        return member == null
087            ? null
088            : Collections.singletonList(member);
089    }
090
091    @Override
092    public void clear() {
093        list.clear();
094    }
095
096    @Override
097    public int size() {
098        return list.size();
099    }
100
101    public int getArity() {
102        return 1;
103    }
104
105    public List<Member> slice(int column) {
106        return list;
107    }
108
109    public TupleList cloneList(int capacity) {
110        return new UnaryTupleList(
111            capacity < 0
112                ? new ArrayList<Member>(list)
113                : new ArrayList<Member>(capacity));
114    }
115
116    public TupleCursor tupleCursor() {
117        return tupleIterator();
118    }
119
120    public TupleIterator tupleIterator() {
121        return new UnaryIterator();
122    }
123
124    public final Iterator<List<Member>> iterator() {
125        return tupleIterator();
126    }
127
128    public TupleList project(int[] destIndices) {
129        // REVIEW: Is 0-ary valid?
130        assert destIndices.length == 1;
131        assert destIndices[0] == 0;
132        return this;
133    }
134
135    public void addTuple(Member... members) {
136        assert members.length == 1;
137        list.add(members[0]);
138    }
139
140    public void addCurrent(TupleCursor tupleIter) {
141        list.add(tupleIter.member(0));
142    }
143
144    @Override
145    public TupleList subList(int fromIndex, int toIndex) {
146        return new ListTupleList(
147            1,
148            list.subList(fromIndex, toIndex));
149    }
150
151    public TupleList withPositionCallback(
152        final PositionCallback positionCallback)
153    {
154        return new UnaryTupleList(
155            new AbstractList<Member>() {
156                public Member get(int index) {
157                    positionCallback.onPosition(index);
158                    return list.get(index);
159                }
160
161                public int size() {
162                    return list.size();
163                }
164
165                public Member set(int index, Member element) {
166                    positionCallback.onPosition(index);
167                    return list.set(index, element);
168                }
169
170                public void add(int index, Member element) {
171                    positionCallback.onPosition(index);
172                    list.add(index, element);
173                }
174
175                public Member remove(int index) {
176                    positionCallback.onPosition(index);
177                    return list.remove(index);
178                }
179            }
180        );
181    }
182
183    /**
184     * Implementation of {@link mondrian.calc.TupleIterator} for {@link UnaryTupleList}.
185     * Based upon AbstractList.Itr, but with concurrent modification checking
186     * removed.
187     */
188    private class UnaryIterator implements TupleIterator {
189        /**
190         * Index of element to be returned by subsequent call to next.
191         */
192        int cursor = 0;
193
194        /**
195         * Index of element returned by most recent call to next or
196         * previous.  Reset to -1 if this element is deleted by a call
197         * to remove.
198         */
199        int lastRet = -1;
200
201        public boolean hasNext() {
202            return cursor != size();
203        }
204
205        public List<Member> next() {
206            try {
207                List<Member> next = get(cursor);
208                lastRet = cursor++;
209                return next;
210            } catch (IndexOutOfBoundsException e) {
211                throw new NoSuchElementException();
212            }
213        }
214
215        public void currentToArray(Member[] members, int offset) {
216            members[offset] = list.get(lastRet);
217        }
218
219        public boolean forward() {
220            if (cursor == size()) {
221                return false;
222            }
223            lastRet = cursor++;
224            return true;
225        }
226
227        public List<Member> current() {
228            return get(lastRet);
229        }
230
231        public int getArity() {
232            return 1;
233        }
234
235        public void remove() {
236            if (lastRet == -1) {
237                throw new IllegalStateException();
238            }
239            try {
240                UnaryTupleList.this.remove(lastRet);
241                if (lastRet < cursor) {
242                    cursor--;
243                }
244                lastRet = -1;
245            } catch (IndexOutOfBoundsException e) {
246                throw new ConcurrentModificationException();
247            }
248        }
249
250        public void setContext(Evaluator evaluator) {
251            evaluator.setContext(list.get(lastRet));
252        }
253
254        public Member member(int column) {
255            assert column == 0;
256            return list.get(lastRet);
257        }
258    }
259}
260
261// End UnaryTupleList.java