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