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) 2002-2005 Julian Hyde 008// Copyright (C) 2005-2013 Pentaho and others 009// All Rights Reserved. 010// 011// jhyde, 21 March, 2002 012*/ 013package mondrian.rolap.agg; 014 015import mondrian.rolap.CellKey; 016 017import java.util.Iterator; 018import java.util.Map; 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 */ 031abstract class DenseSegmentDataset implements SegmentDataset { 032 private final SegmentAxis[] axes; 033 protected final int[] axisMultipliers; 034 035 /** 036 * Creates a DenseSegmentDataset. 037 * 038 * @param axes Segment axes, containing actual column values 039 */ 040 DenseSegmentDataset(SegmentAxis[] axes) { 041 this.axes = axes; 042 this.axisMultipliers = computeAxisMultipliers(); 043 } 044 045 private int[] computeAxisMultipliers() { 046 final int[] axisMultipliers = new int[axes.length]; 047 int multiplier = 1; 048 for (int i = axes.length - 1; i >= 0; --i) { 049 final SegmentAxis axis = axes[i]; 050 axisMultipliers[i] = multiplier; 051 multiplier *= axis.getKeys().length; 052 } 053 return axisMultipliers; 054 } 055 056 public final double getBytes() { 057 // assume a slot, key, and value are each 4 bytes 058 return getSize() * 12; 059 } 060 061 public Iterator<Map.Entry<CellKey, Object>> iterator() { 062 return new DenseSegmentDatasetIterator(); 063 } 064 065 protected abstract Object getObject(int i); 066 067 protected final int getOffset(int[] keys) { 068 return CellKey.Generator.getOffset(keys, axisMultipliers); 069 } 070 071 protected final int getOffset(Object[] keys) { 072 int offset = 0; 073outer: 074 for (int i = 0; i < keys.length; i++) { 075 SegmentAxis axis = axes[i]; 076 Object[] ks = axis.getKeys(); 077 final int axisLength = ks.length; 078 offset *= axisLength; 079 Object value = keys[i]; 080 for (int j = 0; j < axisLength; j++) { 081 if (ks[j].equals(value)) { 082 offset += j; 083 continue outer; 084 } 085 } 086 return -1; // not found 087 } 088 return offset; 089 } 090 091 public Object getObject(CellKey pos) { 092 throw new UnsupportedOperationException(); 093 } 094 095 public int getInt(CellKey pos) { 096 throw new UnsupportedOperationException(); 097 } 098 099 public double getDouble(CellKey pos) { 100 throw new UnsupportedOperationException(); 101 } 102 103 protected abstract int getSize(); 104 105 /** 106 * Iterator over a DenseSegmentDataset. 107 * 108 * <p>This is a 'cheap' implementation 109 * which doesn't allocate a new Entry every step: it just returns itself. 110 * The Entry must therefore be used immediately, before calling 111 * {@link #next()} again. 112 */ 113 private class DenseSegmentDatasetIterator implements 114 Iterator<Map.Entry<CellKey, Object>>, 115 Map.Entry<CellKey, Object> 116 { 117 private final int last = getSize() - 1; 118 private int i = -1; 119 private final int[] ordinals; 120 121 DenseSegmentDatasetIterator() { 122 ordinals = new int[axes.length]; 123 ordinals[ordinals.length - 1] = -1; 124 } 125 126 public boolean hasNext() { 127 return i < last; 128 } 129 130 public Map.Entry<CellKey, Object> next() { 131 ++i; 132 int k = ordinals.length - 1; 133 while (k >= 0) { 134 if (ordinals[k] < axes[k].getKeys().length - 1) { 135 ++ordinals[k]; 136 break; 137 } else { 138 ordinals[k] = 0; 139 --k; 140 } 141 } 142 return this; 143 } 144 145 // implement Iterator 146 public void remove() { 147 throw new UnsupportedOperationException(); 148 } 149 150 // implement Entry 151 public CellKey getKey() { 152 return CellKey.Generator.newCellKey(ordinals); 153 } 154 155 // implement Entry 156 public Object getValue() { 157 return getObject(i); 158 } 159 160 // implement Entry 161 public Object setValue(Object value) { 162 throw new UnsupportedOperationException(); 163 } 164 } 165} 166 167// End DenseSegmentDataset.java