001    /*
002    // $Id: //open/mondrian/src/main/mondrian/olap/fun/HeadTailFunDef.java#4 $
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-2008 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.calc.*;
013    import mondrian.calc.impl.AbstractListCalc;
014    import mondrian.calc.impl.ConstantCalc;
015    import mondrian.mdx.ResolvedFunCall;
016    import mondrian.olap.Evaluator;
017    import mondrian.olap.FunDef;
018    import mondrian.util.UnsupportedList;
019    
020    import java.util.*;
021    
022    /**
023     * Definition of the <code>Head</code> and <code>Tail</code>
024     * MDX builtin functions.
025     *
026     * @author jhyde
027     * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/HeadTailFunDef.java#4 $
028     * @since Mar 23, 2006
029     */
030    class HeadTailFunDef extends FunDefBase {
031        static final Resolver TailResolver = new ReflectiveMultiResolver(
032                "Tail",
033                "Tail(<Set>[, <Count>])",
034                "Returns a subset from the end of a set.",
035                new String[] {"fxx", "fxxn"},
036                HeadTailFunDef.class);
037    
038        static final Resolver HeadResolver = new ReflectiveMultiResolver(
039                "Head",
040                "Head(<Set>[, < Numeric Expression >])",
041                "Returns the first specified number of elements in a set.",
042                new String[] {"fxx", "fxxn"},
043                HeadTailFunDef.class);
044    
045        private final boolean head;
046    
047        public HeadTailFunDef(FunDef dummyFunDef) {
048            super(dummyFunDef);
049            head = dummyFunDef.getName().equals("Head");
050        }
051    
052        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
053            final ListCalc listCalc =
054                    compiler.compileList(call.getArg(0));
055            final IntegerCalc integerCalc =
056                    call.getArgCount() > 1 ?
057                    compiler.compileInteger(call.getArg(1)) :
058                    ConstantCalc.constantInteger(1);
059            if (head) {
060                return new AbstractListCalc(call, new Calc[] {listCalc, integerCalc}) {
061                    public List evaluateList(Evaluator evaluator) {
062                        List list = listCalc.evaluateList(evaluator);
063                        int count = integerCalc.evaluateInteger(evaluator);
064                        return head(count, list);
065                    }
066                };
067            } else {
068                return new AbstractListCalc(call, new Calc[] {listCalc, integerCalc}) {
069    
070                    public List evaluateList(Evaluator evaluator) {
071                        List list = listCalc.evaluateList(evaluator);
072                        int count = integerCalc.evaluateInteger(evaluator);
073                        return tail(count, list);
074                    }
075                };
076            }
077        }
078    
079        static List tail(final int count, final List members) {
080            assert members != null;
081            final int memberCount = members.size();
082            if (count >= memberCount) {
083                return members;
084            }
085            if (count <= 0) {
086                return Collections.EMPTY_LIST;
087            }
088            return new UnsupportedList<Object>() {
089                public boolean isEmpty() {
090                    return false;
091                }
092    
093                public int size() {
094                    return Math.min(count, members.size());
095                }
096    
097                public Object get(final int idx) {
098                    final int index = idx + memberCount - count;
099                    return members.get(index);
100                }
101    
102                public Iterator<Object> iterator() {
103                    return new ItrUnknownSize();
104                }
105            };
106        }
107    
108        static List head(final int count, final List members) {
109            assert members != null;
110            if (count <= 0) {
111                return Collections.EMPTY_LIST;
112            }
113            return new UnsupportedList<Object>() {
114                public boolean isEmpty() {
115                    return false;
116                }
117    
118                public int size() {
119                    return Math.min(count, members.size());
120                }
121    
122                public Object get(final int index) {
123                    if (index >= count) {
124                        throw new IndexOutOfBoundsException();
125                    }
126                    return members.get(index);
127                }
128                public Iterator<Object> iterator() {
129                    return new ItrUnknownSize();
130                }
131            };
132        }
133    }
134    
135    // End HeadTailFunDef.java