001    /*
002    // $Id: //open/mondrian/src/main/mondrian/olap/fun/SubsetFunDef.java#1 $
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) 2006-2006 Julian Hyde
007    // All Rights Reserved.
008    // You must accept the terms of that agreement to use this software.
009    */
010    package mondrian.olap.fun;
011    
012    import mondrian.olap.FunDef;
013    import mondrian.olap.Evaluator;
014    import mondrian.calc.Calc;
015    import mondrian.calc.ExpCompiler;
016    import mondrian.calc.ListCalc;
017    import mondrian.calc.IntegerCalc;
018    import mondrian.calc.impl.AbstractListCalc;
019    import mondrian.mdx.ResolvedFunCall;
020    
021    import java.util.List;
022    import java.util.Collections;
023    
024    /**
025     * Definition of the <code>Subset</code> MDX function.
026     *
027     * @author jhyde
028     * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/SubsetFunDef.java#1 $
029     * @since Mar 23, 2006
030     */
031    class SubsetFunDef extends FunDefBase {
032        static final ReflectiveMultiResolver Resolver = new ReflectiveMultiResolver(
033                "Subset",
034                "Subset(<Set>, <Start>[, <Count>])",
035                "Returns a subset of elements from a set.",
036                new String[] {"fxxn", "fxxnn"},
037                SubsetFunDef.class);
038    
039        public SubsetFunDef(FunDef dummyFunDef) {
040            super(dummyFunDef);
041        }
042    
043        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
044            final ListCalc listCalc =
045                    compiler.compileList(call.getArg(0));
046            final IntegerCalc startCalc =
047                    compiler.compileInteger(call.getArg(1));
048            final IntegerCalc countCalc =
049                    call.getArgCount() > 2 ?
050                    compiler.compileInteger(call.getArg(2)) :
051                    null;
052            return new AbstractListCalc(call, new Calc[] {listCalc, startCalc, countCalc}) {
053                public List evaluateList(Evaluator evaluator) {
054                    final List list =
055                            listCalc.evaluateList(evaluator);
056                    final int start =
057                            startCalc.evaluateInteger(evaluator);
058                    int end;
059                    if (countCalc != null) {
060                        final int count =
061                            countCalc.evaluateInteger(evaluator);
062                        end = start + count;
063                    } else {
064                        end = list.size();
065                    }
066                    if (end > list.size()) {
067                        end = list.size();
068                    }
069                    if (start >= end || start < 0) {
070                        return Collections.EMPTY_LIST;
071                    }
072                    assert 0 <= start;
073                    assert start < end;
074                    assert end <= list.size();
075                    if (start == 0 && end == list.size()) {
076                        return list;
077                    } else {
078                        return list.subList(start, end);
079                    }
080                }
081            };
082        }
083    }
084    
085    // End SubsetFunDef.java