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-2013 Pentaho and others
008// All Rights Reserved.
009*/
010package mondrian.rolap.agg;
011
012import mondrian.rolap.CellKey;
013import mondrian.spi.SegmentBody;
014import mondrian.util.Pair;
015
016import java.util.*;
017
018/**
019 * Abstract implementation of a SegmentBody.
020 *
021 * @author LBoudreau
022 */
023abstract class AbstractSegmentBody implements SegmentBody {
024    private static final long serialVersionUID = -7094121704771005640L;
025
026    protected final SortedSet<Comparable>[] axisValueSets;
027    private final boolean[] nullAxisFlags;
028
029    public AbstractSegmentBody(
030        List<Pair<SortedSet<Comparable>, Boolean>> axes)
031    {
032        super();
033        //noinspection unchecked
034        this.axisValueSets = new SortedSet[axes.size()];
035        this.nullAxisFlags = new boolean[axes.size()];
036        for (int i = 0; i < axes.size(); i++) {
037            Pair<SortedSet<Comparable>, Boolean> pair = axes.get(i);
038            axisValueSets[i] = pair.left;
039            nullAxisFlags[i] = pair.right;
040        }
041    }
042
043    public SortedSet<Comparable>[] getAxisValueSets() {
044        return axisValueSets;
045    }
046
047    public boolean[] getNullAxisFlags() {
048        return nullAxisFlags;
049    }
050
051    public Map<CellKey, Object> getValueMap() {
052        return new AbstractMap<CellKey, Object>() {
053            public Set<Entry<CellKey, Object>> entrySet() {
054                return new AbstractSet<Entry<CellKey, Object>>() {
055                    public Iterator<Entry<CellKey, Object>> iterator() {
056                        return new SegmentBodyIterator();
057                    }
058
059                    public int size() {
060                        return getSize();
061                    }
062                };
063            }
064        };
065    }
066
067    public Object getValueArray() {
068        throw new UnsupportedOperationException(
069            "This method is only supported for dense segments");
070    }
071
072    public BitSet getNullValueIndicators() {
073        throw new UnsupportedOperationException(
074            "This method is only supported for dense segments "
075            + "of native values");
076    }
077
078    protected abstract int getSize();
079
080    protected abstract Object getObject(int i);
081
082    /**
083     * Iterator over all (cellkey, value) pairs in this data set.
084     */
085    private class SegmentBodyIterator
086        implements Iterator<Map.Entry<CellKey, Object>>
087    {
088        private int i = -1;
089        private final int[] ordinals;
090        private final int size = getSize();
091        private boolean hasNext = true;
092        private Object next;
093
094        SegmentBodyIterator() {
095            ordinals = new int[axisValueSets.length];
096            ordinals[ordinals.length - 1] = -1;
097            moveToNext();
098        }
099
100        public boolean hasNext() {
101            return hasNext;
102        }
103
104        public Map.Entry<CellKey, Object> next() {
105            Pair<CellKey, Object> o =
106                Pair.of(CellKey.Generator.newCellKey(ordinals), next);
107            moveToNext();
108            return o;
109        }
110
111        private void moveToNext() {
112            for (;;) {
113                ++i;
114                if (i >= size) {
115                    hasNext = false;
116                    return;
117                }
118                int k = ordinals.length - 1;
119                while (k >= 0) {
120                    if (ordinals[k] < axisValueSets[k].size() - 1) {
121                        ++ordinals[k];
122                        break;
123                    } else {
124                        ordinals[k] = 0;
125                        --k;
126                    }
127                }
128                next = getObject(i);
129                if (next != null) {
130                    return;
131                }
132            }
133        }
134
135        public void remove() {
136            throw new UnsupportedOperationException();
137        }
138    }
139}
140
141// End AbstractSegmentBody.java