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) 2006-2011 Pentaho
008// All Rights Reserved.
009*/
010package mondrian.olap.fun;
011
012import mondrian.calc.*;
013import mondrian.calc.impl.AbstractListCalc;
014import mondrian.calc.impl.ConstantCalc;
015import mondrian.mdx.ResolvedFunCall;
016import mondrian.olap.Evaluator;
017import mondrian.olap.FunDef;
018
019/**
020 * Definition of the <code>Head</code> and <code>Tail</code>
021 * MDX builtin functions.
022 *
023 * @author jhyde
024 * @since Mar 23, 2006
025 */
026class HeadTailFunDef extends FunDefBase {
027    static final Resolver TailResolver =
028        new ReflectiveMultiResolver(
029            "Tail",
030            "Tail(<Set>[, <Count>])",
031            "Returns a subset from the end of a set.",
032            new String[] {"fxx", "fxxn"},
033            HeadTailFunDef.class);
034
035    static final Resolver HeadResolver =
036        new ReflectiveMultiResolver(
037            "Head",
038            "Head(<Set>[, < Numeric Expression >])",
039            "Returns the first specified number of elements in a set.",
040            new String[] {"fxx", "fxxn"},
041            HeadTailFunDef.class);
042
043    private final boolean head;
044
045    public HeadTailFunDef(FunDef dummyFunDef) {
046        super(dummyFunDef);
047        head = dummyFunDef.getName().equals("Head");
048    }
049
050    public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
051        final ListCalc listCalc =
052            compiler.compileList(call.getArg(0));
053        final IntegerCalc integerCalc =
054            call.getArgCount() > 1
055            ? compiler.compileInteger(call.getArg(1))
056            : ConstantCalc.constantInteger(1);
057        if (head) {
058            return new AbstractListCalc(
059                call, new Calc[] {listCalc, integerCalc})
060            {
061                public TupleList evaluateList(Evaluator evaluator) {
062                    final int savepoint = evaluator.savepoint();
063                    try {
064                        evaluator.setNonEmpty(false);
065                        TupleList list = listCalc.evaluateList(evaluator);
066                        int count = integerCalc.evaluateInteger(evaluator);
067                        return head(count, list);
068                    } finally {
069                        evaluator.restore(savepoint);
070                    }
071                }
072            };
073        } else {
074            return new AbstractListCalc(
075                call, new Calc[] {listCalc, integerCalc})
076            {
077                public TupleList evaluateList(Evaluator evaluator) {
078                    final int savepoint = evaluator.savepoint();
079                    try {
080                        evaluator.setNonEmpty(false);
081                        TupleList list = listCalc.evaluateList(evaluator);
082                        int count = integerCalc.evaluateInteger(evaluator);
083                        return tail(count, list);
084                    } finally {
085                        evaluator.restore(savepoint);
086                    }
087                }
088            };
089        }
090    }
091
092    static TupleList tail(final int count, final TupleList members) {
093        assert members != null;
094        final int memberCount = members.size();
095        if (count >= memberCount) {
096            return members;
097        }
098        if (count <= 0) {
099            return TupleCollections.emptyList(members.getArity());
100        }
101        return members.subList(members.size() - count, members.size());
102    }
103
104    static TupleList head(final int count, final TupleList members) {
105        assert members != null;
106        if (count <= 0) {
107            return TupleCollections.emptyList(members.getArity());
108        }
109        return members.subList(0, Math.min(count, members.size()));
110    }
111}
112
113// End HeadTailFunDef.java