Exemplo n.º 1
0
        /// <summary>
        /// Implement the skipping. We have a main limitation: we currently know only how to implement integer skipping.
        /// We implement with "if" statements to support composability, even if it means running longer in the end...
        /// We actually return nothing when goes - we aren't really a final result the way "Count" is.
        /// </summary>
        /// <param name="resultOperator"></param>
        /// <param name="queryModel"></param>
        /// <param name="_codeEnv"></param>
        /// <returns></returns>
        public void ProcessResultOperator(ResultOperatorBase resultOperator, QueryModel queryModel, IGeneratedQueryCode codeEnv, ICodeContext codeContext, CompositionContainer container)
        {
            ///
            /// Quick checks to make sure
            /// 

            if (codeEnv == null)
                throw new ArgumentNullException("codeEnv cannot be null");

            var take = resultOperator as TakeResultOperator;
            var skip = resultOperator as SkipResultOperator;

            if (take == null && skip == null)
            {
                throw new ArgumentNullException("resultOperator must not be null and must represent either a take or a skip operation!");
            }

            if (take != null && take.Count.Type != typeof(int))
                throw new ArgumentException("Take operator count must be an integer!");
            if (skip != null && skip.Count.Type != typeof(int))
                throw new ArgumentException("Skip operator count must be an integer!");

            // If this is a "global" take, then we need to declare the variable a bit specially.
            // Global: we have a limit on the number of objects that goes across events. We test this by seeing if this
            // is a sub-query that is registered (or not).
            var isGlobalTake = codeContext.IsInTopLevelQueryModel(queryModel);

            // Now, we create a count variable and that is how we will tell if we are still skipping or
            // taking. It must be declared in the current block, before our current code! :-)

            var counter = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int), otherDependencies: codeContext.LoopIndexVariable.Return<IDeclaredParameter>());
            if (isGlobalTake)
            {
                counter.DeclareAsStatic = true;
                codeEnv.Add(counter);
            } else
            {
                codeEnv.AddOutsideLoop(counter);
            }

            var comparison = StatementIfOnCount.ComparisonOperator.LessThanEqual;
            IValue limit = null;
            if (skip != null)
            {
                comparison = StatementIfOnCount.ComparisonOperator.GreaterThan;
                limit = ExpressionToCPP.GetExpression(skip.Count, codeEnv, codeContext, container);
            }
            else
            {
                limit = ExpressionToCPP.GetExpression(take.Count, codeEnv, codeContext, container);
            }

            codeEnv.Add(new StatementIfOnCount(counter, limit, comparison));

            ///
            /// We are particularly fortunate here. We don't have to update the Loop variable - whatever it is, is
            /// still the right one! Normally we'd have to futz with the LoopVariable in code context because we
            /// were iterating over something new. :-) Easy!
            /// 
        }
        /// <summary>
        /// Take the incoming stream of items, and send them along! :-)
        /// </summary>
        /// <param name="resultOperator"></param>
        /// <param name="queryModel"></param>
        /// <param name="_codeEnv"></param>
        /// <param name="_codeContext"></param>
        /// <param name="container"></param>
        public void ProcessResultOperator(ResultOperatorBase resultOperator, QueryModel queryModel, IGeneratedQueryCode gc, ICodeContext cc, CompositionContainer container)
        {
            //
            // Some basic checks on the input.
            //

            if (cc == null)
            {
                throw new ArgumentNullException("cc");
            }
            if (gc == null)
            {
                throw new ArgumentNullException("gc");
            }
            if (cc.LoopVariable == null)
            {
                throw new ArgumentNullException("No defined loop variable!");
            }

            //
            // Get the indexer that is being used to access things. We will just push that onto a temp vector of int's. That will be
            // a list of the items that we want to come back and look at. That said, once done we need to pop-up one level in our
            // depth.
            //

            var arrayRecord = DeclarableParameter.CreateDeclarableParameterArrayExpression(typeof(int));

            gc.AddOutsideLoop(arrayRecord);

            var recordIndexStatement = new Statements.StatementRecordIndicies(ExpressionToCPP.GetExpression(cc.LoopIndexVariable.AsExpression(), gc, cc, container), arrayRecord);

            gc.Add(recordIndexStatement);

            gc.Pop();

            //
            // Now, we go down one loop and run over the pairs with a special loop.
            //

            var index1        = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int));
            var index2        = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int));
            var indexIterator = new Statements.StatementPairLoop(arrayRecord, index1, index2);

            gc.Add(indexIterator);

            //
            // Finally, build the resulting loop variable. For now it is just a tuple, which is basically the formed expression we started with,
            // but with the other index properties. Other bits will have to do the translation for us. :-)
            //

            var item1 = cc.LoopVariable.ReplaceSubExpression(cc.LoopIndexVariable.AsExpression(), index1);
            var item2 = cc.LoopVariable.ReplaceSubExpression(cc.LoopIndexVariable.AsExpression(), index2);

            var tupleType = typeof(Tuple <,>).MakeGenericType(cc.LoopVariable.Type, cc.LoopVariable.Type);
            var newTuple  = Expression.New(tupleType.GetConstructor(new Type[] { cc.LoopVariable.Type, cc.LoopVariable.Type }), item1, item2);

            cc.SetLoopVariable(newTuple, null);
        }
Exemplo n.º 3
0
        /// <summary>
        /// Process the grouping operator. We have to sort through the items, group them, and then
        /// create an object we can be translated later to access the items or the Key. We need to return
        /// an IEnumerable<IGrouping<TKey, TElement>>... As a result, this is one of those operators that has
        /// a fair amount of implementation in other parts of the re-linq structure.
        /// </summary>
        /// <param name="resultOperator"></param>
        /// <param name="queryModel"></param>
        /// <param name="gc"></param>
        /// <param name="cc"></param>
        /// <param name="container"></param>
        /// <returns></returns>
        /// <remarks>
        /// re-linq blog post that shows the format of the query we are dealing with: https://www.re-motion.org/blogs/mix/2009/09/01/re-linq-how-to-support-ldquogroup-intordquo-with-aggregates
        /// Not as useful:
        /// Code for the result operator (including in-memory execution): https://svn.re-motion.org/svn/Remotion/trunk/Relinq/Core/Clauses/ResultOperators/GroupResultOperator.cs
        /// Unit tests for the result operator: https://www.re-motion.org/fisheye/browse/~raw,r=17871/Remotion/trunk/Remotion/Data/Linq.UnitTests/Linq/SqlBackend/SqlPreparation/ResultOperatorHandlers/GroupResultOperatorHandlerTest.cs
        /// </remarks>
        System.Linq.Expressions.Expression IQVScalarResultOperator.ProcessResultOperator(ResultOperatorBase resultOperator, QueryModel queryModel, IGeneratedQueryCode gc, ICodeContext cc, CompositionContainer container)
        {
            //
            // Basic checks
            //

            var groupOp = resultOperator as GroupResultOperator;

            if (groupOp == null)
            {
                throw new ArgumentNullException("resultOperator");
            }

            if (!groupOp.KeySelector.Type.IsNumberType())
            {
                throw new InvalidOperationException(string.Format("Don't know how to group by type '{0}'.", groupOp.KeySelector.Type.Name));
            }

            //
            // First, record all the indicies and the values. This is what we are going to be grouping.
            //

            var mapRecord = DeclarableParameter.CreateDeclarableParameterMapExpression(groupOp.KeySelector.Type, typeof(int).MakeArrayType());

            gc.AddOutsideLoop(mapRecord);

            var savePairValues = new StatementRecordPairValues(mapRecord,
                                                               ExpressionToCPP.GetExpression(groupOp.KeySelector, gc, cc, container),
                                                               ExpressionToCPP.GetExpression(cc.LoopIndexVariable.AsExpression(), gc, cc, container));

            gc.Add(savePairValues);

            gc.Pop();

            //
            // Now create the object that will be handed back for later parsing. This should contain the info that is needed to do the
            // actual looping over the groups when it is requested.
            //

            var t_return = typeof(GroupByTypeTagEnum <int, int>).GetGenericTypeDefinition().MakeGenericType(new Type[] { groupOp.KeySelector.Type, groupOp.ElementSelector.Type });
            var ctor     = t_return.GetConstructor(new Type[] { });
            var o        = ctor.Invoke(new object[] { }) as BaseGroupInfo;

            o.MapRecord                    = mapRecord;
            o.TargetExpression             = groupOp.ElementSelector;
            o.TargetExpressionLoopVariable = cc.LoopIndexVariable;

            return(Expression.Constant(o, t_return));
        }
        /// <summary>
        /// Take the incoming stream of items, and send them along! :-)
        /// </summary>
        /// <param name="resultOperator"></param>
        /// <param name="queryModel"></param>
        /// <param name="_codeEnv"></param>
        /// <param name="_codeContext"></param>
        /// <param name="container"></param>
        public void ProcessResultOperator(ResultOperatorBase resultOperator, QueryModel queryModel, IGeneratedQueryCode gc, ICodeContext cc, CompositionContainer container)
        {
            //
            // Some basic checks on the input.
            //

            if (cc == null)
                throw new ArgumentNullException("cc");
            if (gc == null)
                throw new ArgumentNullException("gc");
            if (cc.LoopVariable == null)
                throw new ArgumentNullException("No defined loop variable!");

            //
            // Get the indexer that is being used to access things. We will just push that onto a temp vector of int's. That will be
            // a list of the items that we want to come back and look at. That said, once done we need to pop-up one level in our
            // depth.
            //

            var arrayRecord = DeclarableParameter.CreateDeclarableParameterArrayExpression(typeof(int));
            gc.AddOutsideLoop(arrayRecord);

            var recordIndexStatement = new Statements.StatementRecordIndicies(ExpressionToCPP.GetExpression(cc.LoopIndexVariable.AsExpression(), gc, cc, container), arrayRecord);
            gc.Add(recordIndexStatement);

            gc.Pop();

            //
            // Now, we go down one loop and run over the pairs with a special loop.
            //

            var index1 = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int));
            var index2 = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int));
            var indexIterator = new Statements.StatementPairLoop(arrayRecord, index1, index2);
            gc.Add(indexIterator);

            //
            // Finally, build the resulting loop variable. For now it is just a tuple, which is basically the formed expression we started with,
            // but with the other index properties. Other bits will have to do the translation for us. :-)
            //

            var item1 = cc.LoopVariable.ReplaceSubExpression(cc.LoopIndexVariable.AsExpression(), index1);
            var item2 = cc.LoopVariable.ReplaceSubExpression(cc.LoopIndexVariable.AsExpression(), index2);

            var tupleType = typeof(Tuple<,>).MakeGenericType(cc.LoopVariable.Type, cc.LoopVariable.Type);
            var newTuple = Expression.New(tupleType.GetConstructor(new Type[] { cc.LoopVariable.Type, cc.LoopVariable.Type }), item1, item2);
            cc.SetLoopVariable(newTuple, null);
        }
Exemplo n.º 5
0
        public Expression ProcessResultOperator(ResultOperatorBase resultOperator, QueryModel queryModel,
                                                IGeneratedQueryCode gc, ICodeContext cc,
                                                CompositionContainer container)
        {
            if (resultOperator == null)
            {
                throw new ArgumentNullException("resultOperator");
            }
            if (cc == null)
            {
                throw new ArgumentNullException("CodeContext can't be null");
            }

            // Determine the type of the result operator we are processing and
            // anything we need to know about it.
            Type sumType;

            sumType = cc.LoopVariable.Type;
            bool doAverage = false;

            if (resultOperator is SumResultOperator)
            {
                doAverage = false;
            }
            else
            {
                doAverage = true;
            }

            // We only know how to sum basic types
            if (!sumType.IsNumberType())
            {
                throw new InvalidOperationException(string.Format("Do not know how to generate C++ to sum type {0}.", sumType.Name));
            }

            var accumulator = DeclarableParameter.CreateDeclarableParameterExpression(sumType);

            accumulator.SetInitialValue("0");

            // Sum and average are a alike in that we are going to add everything we see up.
            var add         = Expression.Add(accumulator, cc.LoopVariable);
            var addResolved = ExpressionToCPP.GetExpression(add, gc, cc, container);

            gc.Add(new StatementAggregate(accumulator, addResolved));

            // If this is a sum no further work needs to happen.
            if (!doAverage)
            {
                return(accumulator);
            }

            // If this is a average then we need to add a simple count.
            var counter = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int));

            counter.SetInitialValue("0");
            var incbyone = Expression.Add(counter, Expression.Constant(1));

            gc.Add(new StatementAggregate(counter, ExpressionToCPP.GetExpression(incbyone, gc, cc, container)));

            // Next, we have to delcare the counter and the accumulator. These are now both temprorary variables.
            if (cc.LoopIndexVariable == null)
            {
                throw new AverageNotAllowedAtTopLevelException("Attempt to use Average at top level, accross events. Not currently implemented.");
            }
            gc.AddOutsideLoop(counter);
            gc.AddOutsideLoop(accumulator);

            // It is an error to average a sequence with no elements. So we need to throw a C++ exception. We need to pop up out of the loop in order
            // to do this.
            // http://msdn.microsoft.com/en-us/library/bb354760.aspx (for specs on Average on this).

            var testForSomething = Expression.Equal(counter, Expression.Constant(0));

            gc.AddAtResultScope(new StatementThrowIfTrue(ExpressionToCPP.GetExpression(testForSomething, gc, cc, container), "Can't take an average of a null sequence"));

            var returnType   = DetermineAverageReturnType(sumType);
            var faccumulator = Expression.Convert(accumulator, returnType);
            var fcount       = Expression.Convert(counter, returnType);
            var divide       = Expression.Divide(faccumulator, fcount);

            // We are done with this calculation, so pop up and out.
            gc.Pop();

            return(divide);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Implement the skipping. We have a main limitation: we currently know only how to implement integer skipping.
        /// We implement with "if" statements to support composability, even if it means running longer in the end...
        /// We actually return nothing when goes - we aren't really a final result the way "Count" is.
        /// </summary>
        /// <param name="resultOperator"></param>
        /// <param name="queryModel"></param>
        /// <param name="_codeEnv"></param>
        /// <returns></returns>
        public void ProcessResultOperator(ResultOperatorBase resultOperator, QueryModel queryModel, IGeneratedQueryCode codeEnv, ICodeContext codeContext, CompositionContainer container)
        {
            ///
            /// Quick checks to make sure
            ///

            if (codeEnv == null)
            {
                throw new ArgumentNullException("codeEnv cannot be null");
            }

            var take = resultOperator as TakeResultOperator;
            var skip = resultOperator as SkipResultOperator;

            if (take == null && skip == null)
            {
                throw new ArgumentNullException("resultOperator must not be null and must represent either a take or a skip operation!");
            }

            if (take != null && take.Count.Type != typeof(int))
            {
                throw new ArgumentException("Take operator count must be an integer!");
            }
            if (skip != null && skip.Count.Type != typeof(int))
            {
                throw new ArgumentException("Skip operator count must be an integer!");
            }

            // If this is a "global" take, then we need to declare the variable a bit specially.
            // Global: we have a limit on the number of objects that goes across events. We test this by seeing if this
            // is a sub-query that is registered (or not).
            var isGlobalTake = codeContext.IsInTopLevelQueryModel(queryModel);

            // Now, we create a count variable and that is how we will tell if we are still skipping or
            // taking. It must be declared in the current block, before our current code! :-)

            var counter = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int), otherDependencies: codeContext.LoopIndexVariable.Return <IDeclaredParameter>());

            if (isGlobalTake)
            {
                counter.DeclareAsStatic = true;
                codeEnv.Add(counter);
            }
            else
            {
                codeEnv.AddOutsideLoop(counter);
            }

            var    comparison = StatementIfOnCount.ComparisonOperator.LessThanEqual;
            IValue limit      = null;

            if (skip != null)
            {
                comparison = StatementIfOnCount.ComparisonOperator.GreaterThan;
                limit      = ExpressionToCPP.GetExpression(skip.Count, codeEnv, codeContext, container);
            }
            else
            {
                limit = ExpressionToCPP.GetExpression(take.Count, codeEnv, codeContext, container);
            }

            codeEnv.Add(new StatementIfOnCount(counter, limit, comparison));

            ///
            /// We are particularly fortunate here. We don't have to update the Loop variable - whatever it is, is
            /// still the right one! Normally we'd have to futz with the LoopVariable in code context because we
            /// were iterating over something new. :-) Easy!
            ///
        }
Exemplo n.º 7
0
        /// <summary>
        /// Code up the min/max result operators. We run the loop out, and then
        /// we return the result whatever it is. We only work when the type is
        /// something simple we can deal with!
        /// </summary>
        /// <param name="resultOperator"></param>
        /// <param name="queryModel"></param>
        /// <param name="_codeEnv"></param>
        /// <param name="_codeContext"></param>
        /// <param name="container"></param>
        /// <returns></returns>
        public Expression ProcessResultOperator(ResultOperatorBase resultOperator, QueryModel queryModel, IGeneratedQueryCode gc, ICodeContext cc, CompositionContainer container)
        {
            ///
            /// Some argument checking
            /// 

            if (cc == null)
                throw new ArgumentNullException("cc");

            if (gc == null)
                throw new ArgumentNullException("gc");

            if (gc.Depth == 1)
                throw new ArgumentException("The Max/Min operators can't be used as result operators for a query - they can only be used in a sub-query");

            ///
            /// Is it min or max?
            /// 

            var minOperator = resultOperator as MinResultOperator;
            var maxOperator = resultOperator as MaxResultOperator;

            if (minOperator == null && maxOperator == null)
                throw new InvalidOperationException("Should always have min or max operator!");

            bool doMax = maxOperator != null;

            bool returnDefaultValue = false;
            if (doMax)
                returnDefaultValue = maxOperator.ReturnDefaultWhenEmpty;
            else
                returnDefaultValue = minOperator.ReturnDefaultWhenEmpty;

            ///
            /// Next, look at the type of the current result that is running.
            /// 

            var valueExpr = queryModel.SelectClause.Selector;
            if (!TimeCanBeCompared(valueExpr.Type))
                throw new ArgumentException(string.Format("I don't know how to fix the min or max of a sequence of '{0}'s", cc.LoopVariable.Type.Name));

            ///
            /// Now, declare two variables, one bool which gets set when we get the first value,
            /// and the other to hold the min/max value! Note that we initalize the variable to
            /// the proper type. We don't declare minmax holder - as it may end up be used
            /// externally.
            /// 

            var vIsFilled = DeclarableParameter.CreateDeclarableParameterExpression(typeof(bool));
            vIsFilled.InitialValue = new ValSimple("false", typeof(bool), null);
            var vMaxMin = DeclarableParameter.CreateDeclarableParameterExpression(valueExpr.Type);
            vMaxMin.InitialValue = new ValSimple("0", typeof(int), null);

            gc.AddOutsideLoop(vIsFilled);

            ///
            /// The expression we want to mimize or maximize
            /// 

            var exprToMinOrMaximize = ExpressionToCPP.GetExpression(valueExpr, gc, cc, container);

            ///
            /// Now, we just have to put the x-checks in there.
            /// 

            var ifStatement = new Statements.StatementMinMaxTest(vIsFilled, vMaxMin, exprToMinOrMaximize, doMax);
            gc.Add(ifStatement);

            return vMaxMin;
        }
Exemplo n.º 8
0
        /// <summary>
        /// Sort the current stream of the query. To do this we run through all the results, sort them,
        /// and then start a new loop.
        /// </summary>
        /// <param name="ordering"></param>
        /// <param name="queryModel"></param>
        /// <param name="orderByClause"></param>
        /// <param name="index"></param>
        public override void VisitOrdering(Ordering ordering, QueryModel queryModel, OrderByClause orderByClause, int index)
        {
            //
            // Only number types can be sorted.
            //

            if (!ordering.Expression.Type.IsNumberType())
            {
                throw new InvalidOperationException(string.Format("Don't know how to sort query by type '{0}'.", ordering.Expression.Type.Name));
            }

            //
            // First, record all the indicies and the values. This is what we are going to be sorting.
            //

            var mapRecord = DeclarableParameter.CreateDeclarableParameterMapExpression(ordering.Expression.Type, _codeContext.LoopIndexVariable.Type.MakeArrayType());

            _codeEnv.AddOutsideLoop(mapRecord);

            var savePairValues = new StatementRecordPairValues(mapRecord,
                                                               ExpressionToCPP.GetExpression(ordering.Expression, _codeEnv, _codeContext, MEFContainer),
                                                               ExpressionToCPP.GetExpression(_codeContext.LoopIndexVariable.AsExpression(), _codeEnv, _codeContext, MEFContainer));

            _codeEnv.Add(savePairValues);

            var otherSavers = _codeEnv.GetUsedQuerySourceVariables(savePairValues, _codeContext.LoopIndexVariable)
                              .Select(v =>
            {
                var mr = DeclarableParameter.CreateDeclarableParameterMapExpression(ordering.Expression.Type, v.Type.MakeArrayType());
                _codeEnv.AddOutsideLoop(mr);
                savePairValues.AddSaver(mr, v);
                return(Tuple.Create(v, mr));
            })
                              .ToArray();

            // Get back to the results level now, where we do the sorting!

            _codeEnv.PopToResultsLevel();

            //
            // Now, we need to sort and loop over the variables in the map. This is a bit of a messy
            // multi-line statement, and it is a compound statement.
            //

            var sortAndRunLoop = new StatementLoopOverSortedPairValue(mapRecord, ordering.OrderingDirection == OrderingDirection.Asc);

            _codeEnv.Add(sortAndRunLoop);

            var pindex = sortAndRunLoop.IndexVariable;
            var lv     = _codeContext.LoopIndexVariable.RawValue;

            _codeContext.Add(lv, pindex);

            foreach (var savers in otherSavers)
            {
                var newVarName = sortAndRunLoop.RestoreOtherSaver(savers.Item2);
                _codeContext.Add(savers.Item1.RawValue, newVarName);
            }

            _codeContext.SetLoopVariable(_codeContext.LoopVariable.ReplaceSubExpression(_codeContext.LoopIndexVariable.AsExpression(), pindex), pindex);
        }
Exemplo n.º 9
0
        /// <summary>
        /// Add the code to do the pair-wise loop.
        /// </summary>
        /// <param name="resultOperator"></param>
        /// <param name="queryModel"></param>
        /// <param name="_codeEnv"></param>
        /// <param name="_codeContext"></param>
        /// <param name="container"></param>
        public void ProcessResultOperator(ResultOperatorBase resultOperator, QueryModel queryModel, IGeneratedQueryCode gc, ICodeContext cc, CompositionContainer container)
        {
            var ro = resultOperator as PairWiseAllResultOperator;
            if (ro == null)
                throw new ArgumentNullException("Result operator is not of PairWiseAll type");

            //
            // First, record all the good indicies for this array
            // 

            var arrayRecord = DeclarableParameter.CreateDeclarableParameterArrayExpression(typeof(int));
            gc.AddOutsideLoop(arrayRecord);

            var recordIndexStatement = new StatementRecordIndicies(ExpressionToCPP.GetExpression(cc.LoopIndexVariable.AsExpression(), gc, cc, container), arrayRecord);
            gc.Add(recordIndexStatement);

            gc.Pop();

            ///
            /// Next, we create a loop that will mark all the guys as "good" that
            /// the pair-wise function. Hopefully the statement below will be efficient and
            /// not double-try anything! The lambda we've been passed we have to evaluate - twice -
            /// for each, and pass it as a "test" to the statement. It will be some horrendus expression
            /// I suppose!
            /// 

            var passAll = DeclarableParameter.CreateDeclarableParameterArrayExpression(typeof(bool));
            gc.Add(passAll);
            var index1 = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int));
            var index2 = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int));

            var index1Lookup = cc.LoopVariable.ReplaceSubExpression(cc.LoopIndexVariable.AsExpression(), index1); //Expression.ArrayIndex(array, index1);
            var index2Lookup = cc.LoopVariable.ReplaceSubExpression(cc.LoopIndexVariable.AsExpression(), index2);//Expression.ArrayIndex(array, index2);

            var callLambda = Expression.Invoke(ro.Test,
                index1Lookup,
                index2Lookup
                );

            var xcheck = new Statements.StatementCheckLoopPairwise(arrayRecord,
                index1, index2, passAll);
            gc.Add(xcheck);
            var test = new Statements.StatementTestLoopPairwise(
                passAll,
                ExpressionToCPP.GetExpression(callLambda, gc, cc, container));
            gc.Add(test);
            gc.Pop();

            //
            // Ok, the result of that will be the array we have here is now filled with the
            // "proper" stuff. That is - we have "true" in everthing that is good. So we will
            // now just loop over that and apply the index as needed.
            //

            var goodIndex = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int));
            gc.Add(goodIndex);
            var loopOverGood = new Statements.StatementLoopOverGood(arrayRecord, passAll, goodIndex);
            gc.Add(loopOverGood);

            cc.SetLoopVariable(cc.LoopVariable.ReplaceSubExpression(cc.LoopIndexVariable.AsExpression(), goodIndex), goodIndex);
        }
Exemplo n.º 10
0
        /// <summary>
        /// Add the code to do the pair-wise loop.
        /// </summary>
        /// <param name="resultOperator"></param>
        /// <param name="queryModel"></param>
        /// <param name="_codeEnv"></param>
        /// <param name="_codeContext"></param>
        /// <param name="container"></param>
        public void ProcessResultOperator(ResultOperatorBase resultOperator, QueryModel queryModel, IGeneratedQueryCode gc, ICodeContext cc, CompositionContainer container)
        {
            var ro = resultOperator as PairWiseAllResultOperator;

            if (ro == null)
            {
                throw new ArgumentNullException("Result operator is not of PairWiseAll type");
            }

            //
            // First, record all the good indicies for this array
            //

            var arrayRecord = DeclarableParameter.CreateDeclarableParameterArrayExpression(typeof(int));

            gc.AddOutsideLoop(arrayRecord);

            var recordIndexStatement = new StatementRecordIndicies(ExpressionToCPP.GetExpression(cc.LoopIndexVariable.AsExpression(), gc, cc, container), arrayRecord);

            gc.Add(recordIndexStatement);

            gc.Pop();

            ///
            /// Next, we create a loop that will mark all the guys as "good" that
            /// the pair-wise function. Hopefully the statement below will be efficient and
            /// not double-try anything! The lambda we've been passed we have to evaluate - twice -
            /// for each, and pass it as a "test" to the statement. It will be some horrendus expression
            /// I suppose!
            ///

            var passAll = DeclarableParameter.CreateDeclarableParameterArrayExpression(typeof(bool));

            gc.Add(passAll);
            var index1 = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int));
            var index2 = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int));

            var index1Lookup = cc.LoopVariable.ReplaceSubExpression(cc.LoopIndexVariable.AsExpression(), index1); //Expression.ArrayIndex(array, index1);
            var index2Lookup = cc.LoopVariable.ReplaceSubExpression(cc.LoopIndexVariable.AsExpression(), index2); //Expression.ArrayIndex(array, index2);

            var callLambda = Expression.Invoke(ro.Test,
                                               index1Lookup,
                                               index2Lookup
                                               );

            var xcheck = new Statements.StatementCheckLoopPairwise(arrayRecord,
                                                                   index1, index2, passAll);

            gc.Add(xcheck);
            var test = new Statements.StatementTestLoopPairwise(
                passAll,
                ExpressionToCPP.GetExpression(callLambda, gc, cc, container));

            gc.Add(test);
            gc.Pop();

            //
            // Ok, the result of that will be the array we have here is now filled with the
            // "proper" stuff. That is - we have "true" in everthing that is good. So we will
            // now just loop over that and apply the index as needed.
            //

            var goodIndex = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int));

            gc.Add(goodIndex);
            var loopOverGood = new Statements.StatementLoopOverGood(arrayRecord, passAll, goodIndex);

            gc.Add(loopOverGood);

            cc.SetLoopVariable(cc.LoopVariable.ReplaceSubExpression(cc.LoopIndexVariable.AsExpression(), goodIndex), goodIndex);
        }
Exemplo n.º 11
0
        /// <summary>
        /// Code up the min/max result operators. We run the loop out, and then
        /// we return the result whatever it is. We only work when the type is
        /// something simple we can deal with!
        /// </summary>
        /// <param name="resultOperator"></param>
        /// <param name="queryModel"></param>
        /// <param name="_codeEnv"></param>
        /// <param name="_codeContext"></param>
        /// <param name="container"></param>
        /// <returns></returns>
        public Expression ProcessResultOperator(ResultOperatorBase resultOperator, QueryModel queryModel, IGeneratedQueryCode gc, ICodeContext cc, CompositionContainer container)
        {
            ///
            /// Some argument checking
            ///

            if (cc == null)
            {
                throw new ArgumentNullException("cc");
            }

            if (gc == null)
            {
                throw new ArgumentNullException("gc");
            }

            if (gc.Depth == 1)
            {
                throw new ArgumentException("The Max/Min operators can't be used as result operators for a query - they can only be used in a sub-query");
            }

            ///
            /// Is it min or max?
            ///

            var minOperator = resultOperator as MinResultOperator;
            var maxOperator = resultOperator as MaxResultOperator;

            if (minOperator == null && maxOperator == null)
            {
                throw new InvalidOperationException("Should always have min or max operator!");
            }

            bool doMax = maxOperator != null;

            bool returnDefaultValue = false;

            if (doMax)
            {
                returnDefaultValue = maxOperator.ReturnDefaultWhenEmpty;
            }
            else
            {
                returnDefaultValue = minOperator.ReturnDefaultWhenEmpty;
            }

            ///
            /// Next, look at the type of the current result that is running.
            ///

            var valueExpr = queryModel.SelectClause.Selector;

            if (!TimeCanBeCompared(valueExpr.Type))
            {
                throw new ArgumentException(string.Format("I don't know how to fix the min or max of a sequence of '{0}'s", cc.LoopVariable.Type.Name));
            }

            ///
            /// Now, declare two variables, one bool which gets set when we get the first value,
            /// and the other to hold the min/max value! Note that we initalize the variable to
            /// the proper type. We don't declare minmax holder - as it may end up be used
            /// externally.
            ///

            var vIsFilled = DeclarableParameter.CreateDeclarableParameterExpression(typeof(bool));

            vIsFilled.InitialValue = new ValSimple("false", typeof(bool), null);
            var vMaxMin = DeclarableParameter.CreateDeclarableParameterExpression(valueExpr.Type);

            vMaxMin.InitialValue = new ValSimple("0", typeof(int), null);

            gc.AddOutsideLoop(vIsFilled);

            ///
            /// The expression we want to mimize or maximize
            ///

            var exprToMinOrMaximize = ExpressionToCPP.GetExpression(valueExpr, gc, cc, container);

            ///
            /// Now, we just have to put the x-checks in there.
            ///

            var ifStatement = new Statements.StatementMinMaxTest(vIsFilled, vMaxMin, exprToMinOrMaximize, doMax);

            gc.Add(ifStatement);

            return(vMaxMin);
        }
Exemplo n.º 12
0
        public Expression ProcessResultOperator(ResultOperatorBase resultOperator, QueryModel queryModel,
            IGeneratedQueryCode gc, ICodeContext cc,
            CompositionContainer container)
        {
            if (resultOperator == null)
                throw new ArgumentNullException("resultOperator");
            if (cc == null)
                throw new ArgumentNullException("CodeContext can't be null");

            //
            // Determine the type of the result operator we are processing and
            // anything we need to know about it.
            //

            Type sumType;
            sumType = cc.LoopVariable.Type;
            bool doAverage = false;

            if (resultOperator is SumResultOperator)
            {
                doAverage = false;
            }
            else
            {
                doAverage = true;
            }

            //
            // We only know how to sum basic types
            //

            if (!sumType.IsNumberType())
            {
                throw new InvalidOperationException(string.Format("Do not know how to generate C++ to sum type {0}.", sumType.Name));
            }

            var accumulator = DeclarableParameter.CreateDeclarableParameterExpression(sumType);
            accumulator.SetInitialValue("0");

            //
            // Now, in the loop we are currently in, we do the "add".
            //

            var add = Expression.Add(accumulator, cc.LoopVariable);

            var addResolved = ExpressionToCPP.GetExpression(add, gc, cc, container);
            gc.Add(new StatementAggregate(accumulator, addResolved));

            //
            // The sum will just be this accumulator - so return it.
            //

            if (!doAverage)
                return accumulator;

            //
            // If this is a average then we need to add a simple count on. Further, we need to declare
            // everything we are going to need for later.
            //

            var counter = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int));
            counter.SetInitialValue("0");
            gc.AddOutsideLoop(counter);
            gc.AddOutsideLoop(accumulator);
            var incbyone = Expression.Add(counter, Expression.Constant(1));
            gc.Add(new StatementAggregate(counter, ExpressionToCPP.GetExpression(incbyone, gc, cc, container)));

            // It is an error to average a sequence with no elements. So we need to throw a C++ exception. We need to pop up out of the loop in order
            // to do this.
            // http://msdn.microsoft.com/en-us/library/bb354760.aspx (for specs on Average on this).

            var testForSomething = Expression.Equal(counter, Expression.Constant(0));
            gc.AddAtResultScope(new StatementThrowIfTrue(ExpressionToCPP.GetExpression(testForSomething, gc, cc, container), "Can't take an average of a null sequence"));

            var returnType = DetermineAverageReturnType(sumType);
            var faccumulator = Expression.Convert(accumulator, returnType);
            var fcount = Expression.Convert(counter, returnType);
            var divide = Expression.Divide(faccumulator, fcount);

            // We are done with this calculation, so pop up and out.
            gc.Pop();

            return divide;
        }