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.TupleList;
013import mondrian.olap.Member;
014
015import java.util.*;
016
017/**
018 * Abstract implementation of a {@link mondrian.calc.TupleList} that stores
019 * tuples in end-to-end format.
020 *
021 * <p>For example, if the arity is 3, the tuples {(A1, B1, C1), (A1, B2, C2)}
022 * will be stored as {A1, B1, C1, A2, B2, C2}. This is memory-efficient (only
023 * one array, compared to 3 arrays or one array per tuple in other
024 * representations), has good locality of reference, and typical operations
025 * require few indirections.
026 *
027 * <p>Concrete subclasses can store the data in various backing lists.
028 *
029 * @author jhyde
030*/
031abstract class AbstractEndToEndTupleList extends AbstractTupleList {
032
033    AbstractEndToEndTupleList(int arity) {
034        super(arity);
035    }
036
037    public TupleList project(final int[] destIndices) {
038        final List<Member> backingList = backingList();
039        final int originalArity = getArity();
040        return new DelegatingTupleList(
041            destIndices.length,
042            new AbstractList<List<Member>>() {
043                public List<Member> get(int index) {
044                    final int n = index * originalArity;
045                    return new AbstractList<Member>() {
046                        public Member get(int index) {
047                            return backingList.get(n + destIndices[index]);
048                        }
049
050                        public int size() {
051                            return destIndices.length;
052                        }
053                    };
054                }
055
056                public int size() {
057                    return backingList.size() / originalArity;
058                }
059            });
060    }
061
062    protected abstract List<Member> backingList();
063
064    @Override
065    public List<Member> set(int index, List<Member> element) {
066        assert mutable;
067        final List<Member> list = backingList();
068        for (int i = 0, startIndex = index * arity; i < arity; i++) {
069            list.set(startIndex + i, element.get(i));
070        }
071        return null; // not compliant with List contract
072    }
073
074    @Override
075    public boolean addAll(Collection<? extends List<Member>> c) {
076        return addAll(size(), c);
077    }
078
079    @Override
080    public boolean addAll(int i, Collection<? extends List<Member>> c) {
081        assert mutable;
082        if (c instanceof AbstractEndToEndTupleList) {
083            return backingList().addAll(
084                i * arity,
085                ((AbstractEndToEndTupleList) c).backingList());
086        }
087        return super.addAll(i, c);
088    }
089
090    @Override
091    public TupleList subList(int fromIndex, int toIndex) {
092        return new ListTupleList(
093            arity,
094            backingList().subList(fromIndex * arity, toIndex * arity));
095    }
096
097    public TupleList withPositionCallback(
098        final PositionCallback positionCallback)
099    {
100        assert !(backingList() instanceof PositionSensingList);
101        return new ListTupleList(
102            arity, new PositionSensingList(positionCallback));
103    }
104
105    private class PositionSensingList extends AbstractList<Member> {
106        private final PositionCallback positionCallback;
107        private final List<Member> backingList = backingList();
108
109        public PositionSensingList(
110            PositionCallback positionCallback)
111        {
112            this.positionCallback = positionCallback;
113        }
114
115        @Override
116        public Member get(int index) {
117            positionCallback.onPosition(index / arity);
118            return backingList.get(index);
119        }
120
121        @Override
122        public int size() {
123            return backingList.size();
124        }
125
126        @Override
127        public Member set(int index, Member element) {
128            assert mutable;
129            positionCallback.onPosition(index / arity);
130            return backingList.set(index, element);
131        }
132
133        @Override
134        public void add(int index, Member element) {
135            assert mutable;
136            positionCallback.onPosition(index);
137            backingList.add(index, element);
138        }
139
140        @Override
141        public Member remove(int index) {
142            assert mutable;
143            positionCallback.onPosition(index);
144            return backingList.remove(index);
145        }
146    }
147}
148
149// End AbstractEndToEndTupleList.java