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