001    /*
002    // $Id: //open/mondrian/src/main/mondrian/rolap/agg/DenseSegmentDataset.java#9 $
003    // This software is subject to the terms of the Common Public License
004    // Agreement, available at the following URL:
005    // http://www.opensource.org/licenses/cpl.html.
006    // Copyright (C) 2002-2002 Kana Software, Inc.
007    // Copyright (C) 2002-2007 Julian Hyde and others
008    // All Rights Reserved.
009    // You must accept the terms of that agreement to use this software.
010    //
011    // jhyde, 21 March, 2002
012    */
013    package mondrian.rolap.agg;
014    
015    import mondrian.rolap.CellKey;
016    
017    import java.util.Map;
018    import java.util.Iterator;
019    
020    /**
021     * A <code>DenseSegmentDataset</code> is a means of storing segment values
022     * which is suitable when most of the combinations of keys have a value
023     * present.
024     *
025     * <p>The storage requirements are as follows. Table requires 1 word per
026     * cell.</p>
027     *
028     * @author jhyde
029     * @since 21 March, 2002
030     * @version $Id: //open/mondrian/src/main/mondrian/rolap/agg/DenseSegmentDataset.java#9 $
031     */
032    class DenseSegmentDataset implements SegmentDataset {
033        private final Segment segment;
034        private final Object[] values; // length == m[0] * ... * m[axes.length-1]
035    
036        DenseSegmentDataset(Segment segment, Object[] values) {
037            this.segment = segment;
038            this.values = values;
039        }
040    
041        public Object get(CellKey key) {
042            int offset = getOffset(key.getOrdinals());
043            return values[offset];
044        }
045    
046        public double getBytes() {
047            // assume a slot, key, and value are each 4 bytes
048            return values.length * 12;
049        }
050    
051        public void put(CellKey key, Object value) {
052            int offset = getOffset(key.getOrdinals());
053            values[offset] = value;
054        }
055    
056        public Iterator<Map.Entry<CellKey, Object>> iterator() {
057            return new Itr();
058        }
059    
060        boolean contains(Object[] keys) {
061            return getOffset(keys) >= 0;
062        }
063    
064        Object get(Object[] keys) {
065            int offset = getOffset(keys);
066            return keys[offset];
067        }
068    
069        void put(Object[] keys, Object value) {
070            int offset = getOffset(keys);
071            keys[offset] = value;
072        }
073    
074        private int getOffset(int[] keys) {
075            int offset = 0;
076            for (int i = 0; i < keys.length; i++) {
077                Aggregation.Axis axis = segment.axes[i];
078                Object[] ks = axis.getKeys();
079                offset *= ks.length;
080                offset += keys[i];
081            }
082            return offset;
083        }
084    
085        private int getOffset(Object[] keys) {
086            int offset = 0;
087    outer:
088            for (int i = 0; i < keys.length; i++) {
089                Aggregation.Axis axis = segment.axes[i];
090                Object[] ks = axis.getKeys();
091                offset *= ks.length;
092                Object value = keys[i];
093                for (int j = 0, axisLength = ks.length; j < axisLength; j++) {
094                    if (ks[j].equals(value)) {
095                        offset += j;
096                        continue outer;
097                    }
098                }
099                return -1; // not found
100            }
101            return offset;
102        }
103    
104        void set(int k, Object o) {
105            values[k] = o;
106        }
107    
108        /**
109         * Iterator over a DenseSegmentDataset.
110         *
111         * <p>This is a 'cheap' implementation
112         * which doesn't allocate a new Entry every step: it just returns itself.
113         * The Entry must therefore be used immediately, before calling
114         * {@link #next()} again.
115         */
116        private class Itr implements
117            Iterator<Map.Entry<CellKey, Object>>,
118            Map.Entry<CellKey, Object>
119        {
120            private int i = -1;
121            private final int[] ordinals;
122            private final CellKey key;
123    
124            Itr() {
125                ordinals = new int[segment.axes.length];
126                ordinals[ordinals.length - 1] = -1;
127                key = CellKey.Generator.newRefCellKey(ordinals);
128            }
129    
130            public boolean hasNext() {
131                return i < values.length - 1;
132            }
133    
134            public Map.Entry<CellKey, Object> next() {
135                ++i;
136                int k = ordinals.length - 1;
137                while (k >= 0) {
138                    if (ordinals[k] < segment.axes[k].getKeys().length - 1) {
139                        ++ordinals[k];
140                        break;
141                    } else {
142                        ordinals[k] = 0;
143                        --k;
144                    }
145                }
146                return this;
147            }
148    
149            // implement Iterator
150            public void remove() {
151                throw new UnsupportedOperationException();
152            }
153    
154            // implement Entry
155            public CellKey getKey() {
156                return key;
157            }
158    
159            // implement Entry
160            public Object getValue() {
161                return values[i];
162            }
163    
164            // implement Entry
165            public Object setValue(Object value) {
166                throw new UnsupportedOperationException();
167            }
168        }
169    }
170    
171    // End DenseSegmentDataset.java