/*
* This software is subject to the terms of the Eclipse Public License v1.0
* Agreement, available at the following URL:
* http://www.eclipse.org/legal/epl-v10.html.
* You must accept the terms of that agreement to use this software.
*
* Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved.
*/
package mondrian.calc.impl;
import mondrian.calc.*;
import mondrian.olap.Evaluator;
import mondrian.olap.Member;
import java.util.*;
/**
* Implementation of {@link TupleList} where the tuples are unary (each tuple
* consists of just one {@link Member}).
*
* <p>It is implemented as a straightforward wrapper on a backing list. You
* can provide the backing list explicitly using the
* {@link #UnaryTupleList(java.util.List)} constructor, and you can access the
* backing list by calling {@link #slice}(0).
*
* @author jhyde
*/
public class UnaryTupleList
extends AbstractList<List<Member>>
implements TupleList
{
final List<Member> list;
/**
* Creates an empty UnaryTupleList.
*/
public UnaryTupleList() {
this(new ArrayList<Member>());
}
/**
* Creates a UnaryTupleList with a given backing list.
*
* @param list Backing list
*/
public UnaryTupleList(List<Member> list) {
this.list = list;
}
public Member get(int slice, int index) {
assert slice == 0;
return list.get(index);
}
@Override
public List<Member> get(int index) {
return Collections.singletonList(list.get(index));
}
@Override
public void add(int index, List<Member> element) {
list.add(index, element.get(0));
}
@Override
public boolean add(List<Member> element) {
return list.add(element.get(0));
}
public TupleList fix() {
return this;
}
@Override
public List<Member> set(int index, List<Member> element) {
final Member member = list.set(index, element.get(0));
return member == null
? null
: Collections.singletonList(member);
}
@Override
public List<Member> remove(int index) {
final Member member = list.remove(index);
return member == null
? null
: Collections.singletonList(member);
}
@Override
public void clear() {
list.clear();
}
@Override
public int size() {
return list.size();
}
public int getArity() {
return 1;
}
public List<Member> slice(int column) {
return list;
}
public TupleList cloneList(int capacity) {
return new UnaryTupleList(
capacity < 0
? new ArrayList<Member>(list)
: new ArrayList<Member>(capacity));
}
public TupleCursor tupleCursor() {
return tupleIterator();
}
public TupleIterator tupleIterator() {
return new UnaryIterator();
}
public final Iterator<List<Member>> iterator() {
return tupleIterator();
}
public TupleList project(int[] destIndices) {
// REVIEW: Is 0-ary valid?
assert destIndices.length == 1;
assert destIndices[0] == 0;
return this;
}
public void addTuple(Member... members) {
assert members.length == 1;
list.add(members[0]);
}
public void addCurrent(TupleCursor tupleIter) {
list.add(tupleIter.member(0));
}
@Override
public TupleList subList(int fromIndex, int toIndex) {
return new ListTupleList(
1,
list.subList(fromIndex, toIndex));
}
public TupleList withPositionCallback(
final PositionCallback positionCallback)
{
return new UnaryTupleList(
new AbstractList<Member>() {
public Member get(int index) {
positionCallback.onPosition(index);
return list.get(index);
}
public int size() {
return list.size();
}
public Member set(int index, Member element) {
positionCallback.onPosition(index);
return list.set(index, element);
}
public void add(int index, Member element) {
positionCallback.onPosition(index);
list.add(index, element);
}
public Member remove(int index) {
positionCallback.onPosition(index);
return list.remove(index);
}
}
);
}
/**
* Implementation of {@link mondrian.calc.TupleIterator} for {@link UnaryTupleList}.
* Based upon AbstractList.Itr, but with concurrent modification checking
* removed.
*/
private class UnaryIterator implements TupleIterator {
/**
* Index of element to be returned by subsequent call to next.
*/
int cursor = 0;
/**
* Index of element returned by most recent call to next or
* previous. Reset to -1 if this element is deleted by a call
* to remove.
*/
int lastRet = -1;
public boolean hasNext() {
return cursor != size();
}
public List<Member> next() {
try {
List<Member> next = get(cursor);
lastRet = cursor++;
return next;
} catch (IndexOutOfBoundsException e) {
throw new NoSuchElementException();
}
}
public void currentToArray(Member[] members, int offset) {
members[offset] = list.get(lastRet);
}
public boolean forward() {
if (cursor == size()) {
return false;
}
lastRet = cursor++;
return true;
}
public List<Member> current() {
return get(lastRet);
}
public int getArity() {
return 1;
}
public void remove() {
if (lastRet == -1) {
throw new IllegalStateException();
}
try {
UnaryTupleList.this.remove(lastRet);
if (lastRet < cursor) {
cursor--;
}
lastRet = -1;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
public void setContext(Evaluator evaluator) {
evaluator.setContext(list.get(lastRet));
}
public Member member(int column) {
assert column == 0;
return list.get(lastRet);
}
}
}
// End UnaryTupleList.java