001    /*
002    // $Id: //open/mondrian/src/main/mondrian/olap/fun/ExceptFunDef.java#3 $
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.mdx.ResolvedFunCall;
015    import mondrian.olap.*;
016    import mondrian.olap.type.*;
017    import mondrian.util.FilteredIterableList;
018    
019    import java.util.*;
020    
021    /**
022     * Definition of the <code>Except</code> MDX function.
023     *
024     * @author jhyde
025     * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/ExceptFunDef.java#3 $
026     * @since Mar 23, 2006
027     */
028    class ExceptFunDef extends FunDefBase {
029        static final ReflectiveMultiResolver Resolver = new ReflectiveMultiResolver(
030                "Except",
031                "Except(<Set1>, <Set2>[, ALL])",
032                "Finds the difference between two sets, optionally retaining duplicates.",
033                new String[]{"fxxx", "fxxxy"},
034                ExceptFunDef.class);
035    
036        public ExceptFunDef(FunDef dummyFunDef) {
037            super(dummyFunDef);
038        }
039    
040        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
041            // todo: implement ALL
042            final ListCalc listCalc0 = compiler.compileList(call.getArg(0));
043            final ListCalc listCalc1 = compiler.compileList(call.getArg(1));
044            final Type elementType = ((SetType) listCalc0.getType()).getElementType();
045            if (elementType instanceof TupleType) {
046                final TupleListCalc tupleListCalc0 = (TupleListCalc) listCalc0;
047                final TupleListCalc tupleListCalc1 = (TupleListCalc) listCalc1;
048                return new AbstractListCalc(call, new Calc[] {listCalc0, listCalc1}) {
049                    public List evaluateList(Evaluator evaluator) {
050                        List<Member[]> list0 =
051                            tupleListCalc0.evaluateTupleList(evaluator);
052                        if (list0.isEmpty()) {
053                            return list0;
054                        }
055                        List<Member[]> list1 = tupleListCalc1.evaluateTupleList(evaluator);
056                        return exceptTuples(list0, list1);
057                    }
058                };
059            } else {
060                final MemberListCalc memberListCalc0 = (MemberListCalc) listCalc0;
061                final MemberListCalc memberListCalc1 = (MemberListCalc) listCalc1;
062                return new AbstractListCalc(call, new Calc[] {listCalc0, listCalc1}) {
063                    public List evaluateList(Evaluator evaluator) {
064                        List<Member> list0 = memberListCalc0.evaluateMemberList(evaluator);
065                        if (list0.isEmpty()) {
066                            return list0;
067                        }
068                        List<Member> list1 = memberListCalc1.evaluateMemberList(evaluator);
069                        return except(list0, list1);
070                    }
071                };
072            }
073        }
074    
075        <T> List<T> except(final List<T> list0, final List<T> list1) {
076            if (list0.size() == 0) {
077                return list0;
078            }
079            final Set<T> set = new HashSet<T>(list1);
080            return new FilteredIterableList<T>(
081                    list0,
082                    new FilteredIterableList.Filter<T>() {
083                        public boolean accept(final T o) {
084                            return !set.contains(o);
085                        }
086                    });
087        }
088    
089        List exceptTuples(final List<Member[]> list0, final List<Member[]> list1) {
090            if (list0.size() == 0) {
091                return list0;
092            }
093            // Because the .equals and .hashCode methods of
094            // Member[] use identity, wrap each tuple in a list.
095            final Set<List<Member>> set = new HashSet<List<Member>>();
096            for (Member[] members : list1) {
097                set.add(Arrays.asList(members));
098            }
099            return new FilteredIterableList<Member[]>(
100                    list0,
101                    new FilteredIterableList.Filter<Member[]>() {
102                        public boolean accept(final Member[] o) {
103                            return !set.contains(Arrays.asList(o));
104                        }
105                    });
106        }
107    }
108    
109    // End ExceptFunDef.java