001 /* 002 // $Id: //open/mondrian/src/main/mondrian/rolap/Modulos.java#5 $ 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) 2005-2008 Julian Hyde 007 // All Rights Reserved. 008 // You must accept the terms of that agreement to use this software. 009 */ 010 package mondrian.rolap; 011 012 import mondrian.olap.Axis; 013 014 /** 015 * Modulos implementations encapsulate algorithms to map between integral 016 * ordinals and position arrays. There are particular implementations for 017 * the most likely cases where the number of axes is 1, 2 and 3 018 * as well as a general implementation. 019 * <p> 020 * Suppose the result is 4 x 3 x 2, then modulo = {1, 4, 12, 24}. 021 * 022 * <p> 023 * Then the ordinal of cell (3, 2, 1) 024 * <p><blockquote><pre> 025 * = (modulo[0] * 3) + (modulo[1] * 2) + (modulo[2] * 1) 026 * = (1 * 3) + (4 * 2) + (12 * 1) 027 * = 23 028 * </pre></blockquote><p> 029 * <p> 030 * Reverse calculation: 031 * <p><blockquote><pre> 032 * p[0] = (23 % modulo[1]) / modulo[0] = (23 % 4) / 1 = 3 033 * p[1] = (23 % modulo[2]) / modulo[1] = (23 % 12) / 4 = 2 034 * p[2] = (23 % modulo[3]) / modulo[2] = (23 % 24) / 12 = 1 035 * </pre></blockquote><p> 036 * 037 * @author jhyde 038 * @version $Id: //open/mondrian/src/main/mondrian/rolap/Modulos.java#5 $ 039 */ 040 public interface Modulos { 041 public class Generator { 042 public static Modulos create(Axis[] axes) { 043 switch (axes.length) { 044 case 0: 045 return new Modulos.Zero(axes); 046 case 1: 047 return new Modulos.One(axes); 048 case 2: 049 return new Modulos.Two(axes); 050 case 3: 051 return new Modulos.Three(axes); 052 default: 053 return new Modulos.Many(axes); 054 } 055 } 056 // Used for testing only 057 public static Modulos createMany(Axis[] axes) { 058 return new Modulos.Many(axes); 059 } 060 public static Modulos createMany(int[] lengths) { 061 return new Modulos.Many(lengths); 062 } 063 } 064 public abstract class Base implements Modulos { 065 protected final int[] modulos; 066 protected Base(final Axis[] axes) { 067 this.modulos = new int[axes.length + 1]; 068 this.modulos[0] = 1; 069 } 070 protected Base(final int[] lengths) { 071 this.modulos = new int[lengths.length + 1]; 072 this.modulos[0] = 1; 073 } 074 public abstract int[] getCellPos(int cellOrdinal); 075 public abstract int getCellOrdinal(int[] pos); 076 077 public String toString() { 078 StringBuilder buf = new StringBuilder(); 079 buf.append('('); 080 for (int i = 0; i < modulos.length; i++) { 081 if (i > 0) { 082 buf.append(','); 083 } 084 buf.append(modulos[i]); 085 } 086 buf.append(')'); 087 return buf.toString(); 088 } 089 } 090 public class Zero extends Base { 091 private static final int[] pos = new int[0]; 092 private Zero(final Axis[] axes) { 093 super(axes); 094 } 095 public final int[] getCellPos(final int cellOrdinal) { 096 return pos; 097 } 098 public final int getCellOrdinal(final int[] pos) { 099 return 0; 100 } 101 } 102 public class One extends Base { 103 private One(final Axis[] axes) { 104 super(axes); 105 106 this.modulos[1] = axes[0].getPositions().size(); 107 } 108 public final int[] getCellPos(final int cellOrdinal) { 109 return new int[] { 110 (cellOrdinal % this.modulos[1]) 111 }; 112 } 113 public final int getCellOrdinal(final int[] pos) { 114 return (pos[0] * modulos[0]); 115 } 116 } 117 public class Two extends Base { 118 private Two(final Axis[] axes) { 119 super(axes); 120 121 int modulo = axes[0].getPositions().size(); 122 this.modulos[1] = modulo; 123 modulo *= axes[1].getPositions().size(); 124 this.modulos[2] = modulo; 125 } 126 public final int[] getCellPos(final int cellOrdinal) { 127 final int[] modulos = this.modulos; 128 return new int[] { 129 (cellOrdinal % modulos[1]), 130 (cellOrdinal % modulos[2]) / modulos[1] 131 }; 132 } 133 public final int getCellOrdinal(final int[] pos) { 134 final int[] modulos = this.modulos; 135 return (pos[0] * modulos[0]) + 136 (pos[1] * modulos[1]); 137 } 138 } 139 public class Three extends Base { 140 private Three(final Axis[] axes) { 141 super(axes); 142 143 int modulo = axes[0].getPositions().size(); 144 this.modulos[1] = modulo; 145 modulo *= axes[1].getPositions().size(); 146 this.modulos[2] = modulo; 147 modulo *= axes[2].getPositions().size(); 148 this.modulos[3] = modulo; 149 } 150 public final int[] getCellPos(final int cellOrdinal) { 151 final int[] modulos = this.modulos; 152 return new int[] { 153 (cellOrdinal % modulos[1]), 154 (cellOrdinal % modulos[2]) / modulos[1], 155 (cellOrdinal % modulos[3]) / modulos[2] 156 }; 157 } 158 public final int getCellOrdinal(final int[] pos) { 159 final int[] modulos = this.modulos; 160 return (pos[0] * modulos[0]) + 161 (pos[1] * modulos[1]) + 162 (pos[2] * modulos[2]); 163 } 164 } 165 public class Many extends Base { 166 private Many(final Axis[] axes) { 167 super(axes); 168 169 int modulo = 1; 170 for (int i = 0; i < axes.length; i++) { 171 modulo *= axes[i].getPositions().size(); 172 this.modulos[i + 1] = modulo; 173 } 174 } 175 private Many(final int[] lengths) { 176 super(lengths); 177 178 int modulo = 1; 179 for (int i = 0; i < lengths.length; i++) { 180 modulo *= lengths[i]; 181 this.modulos[i + 1] = modulo; 182 } 183 } 184 public int[] getCellPos(final int cellOrdinal) { 185 final int[] modulos = this.modulos; 186 final int size = modulos.length - 1; 187 final int[] pos = new int[size]; 188 for (int i = 0; i < size; i++) { 189 pos[i] = (cellOrdinal % modulos[i + 1]) / modulos[i]; 190 } 191 return pos; 192 } 193 public int getCellOrdinal(final int[] pos) { 194 final int[] modulos = this.modulos; 195 final int size = modulos.length - 1; 196 int ordinal = 0; 197 for (int i = 0; i < size; i++) { 198 ordinal += pos[i] * modulos[i]; 199 } 200 return ordinal; 201 } 202 } 203 204 /** 205 * Converts a cell ordinal to a set of cell coordinates. Converse of 206 * {@link #getCellOrdinal}. For example, if this result is 10 x 10 x 10, 207 * then cell ordinal 537 has coordinates (5, 3, 7). 208 * 209 * @param cellOrdinal Cell ordinal 210 * @return cell coordinates 211 */ 212 int[] getCellPos(int cellOrdinal); 213 214 /** 215 * Converts a set of cell coordinates to a cell ordinal. Converse of 216 * {@link #getCellPos}. 217 * 218 * @param pos Cell coordinates 219 * @return cell ordinal 220 */ 221 int getCellOrdinal(int[] pos); 222 } 223 224 // End Modulos.java