private bool ContainsAncestor(FeatureExpressionInternal candidate, List <FeatureExpressionInternal> validFeature)
        {
            if (candidate.Source.Parent == null)
            {
                return(false);
            }

            if (validFeature.Any(valid => object.ReferenceEquals(valid.Source, candidate.Source.Parent)))
            {
                return(true);
            }

            var parent = this.allFeatures.First(f => object.ReferenceEquals(f.Source, candidate.Source.Parent));

            return(ContainsAncestor(parent, validFeature));
        }
Example #2
0
        /// <summary>
        /// Instantiate the meta information object such as <see cref="PreHashedFeature"/>
        /// for a given feature.
        /// </summary>
        /// <param name="featureInternal">The feature.</param>
        /// <param name="namespace">The namespace.</param>
        /// <returns>The "new" expression for the meta information object.</returns>
        private Expression CreateFeature(FeatureExpressionInternal featureInternal, Expression @namespace)
        {
            FeatureExpression feature = featureInternal.Source;
            var metaFeatureType       = featureInternal.MarshalMethod.MetaFeatureType;

            if (metaFeatureType.IsGenericType && metaFeatureType.GetGenericTypeDefinition() == typeof(EnumerizedFeature <>))
            {
                // preemptively calculate all hashes for each enum value
                var featureParameter = Expression.Parameter(metaFeatureType);
                var valueParameter   = Expression.Parameter(feature.FeatureType);

                var body = new List <Expression>();

                var hashVariables = new List <ParameterExpression>();
                foreach (var value in Enum.GetValues(feature.FeatureType))
                {
                    var hashVar = Expression.Variable(typeof(UInt64));
                    hashVariables.Add(hashVar);

                    // CODE hashVar = feature.FeatureHashInternal(value);
                    body.Add(Expression.Assign(hashVar,
                                               Expression.Call(featureParameter,
                                                               metaFeatureType.GetMethod("FeatureHashInternal"),
                                                               Expression.Constant(value))));
                }

                var cases = Enum.GetValues(feature.FeatureType)
                            .Cast <object>()
                            .Zip(hashVariables, (value, hash) => Expression.SwitchCase(
                                     hash,
                                     Expression.Constant(value, feature.FeatureType)))
                            .ToArray();

                // expand the switch(value) { case enum1: return hash1; .... }
                var hashSwitch = Expression.Switch(valueParameter,
                                                   Expression.Block(Expression.Throw(Expression.New(typeof(NotSupportedException))), Expression.Constant((UInt64)0, typeof(UInt64))),
                                                   cases);

                // CODE return value => switch(value) { .... }
                body.Add(Expression.Lambda(hashSwitch, valueParameter));

                return(CreateNew(
                           metaFeatureType,
                           this.vwParameter,
                           @namespace,
                           Expression.Constant(feature.Name, typeof(string)),
                           Expression.Constant(feature.AddAnchor),
                           Expression.Constant(feature.Dictify),
                           Expression.Lambda(Expression.Block(hashVariables, body), featureParameter)));
            }
            else if (metaFeatureType == typeof(PreHashedFeature))
            {
                // CODE new PreHashedFeature(vw, namespace, "Name", "AddAnchor");
                return(CreateNew(
                           typeof(PreHashedFeature),
                           this.vwParameter,
                           @namespace,
                           Expression.Constant(feature.Name, typeof(string)),
                           Expression.Constant(feature.AddAnchor),
                           Expression.Constant(feature.Dictify)));
            }
            else
            {
                // CODE new Feature("Name", ...)
                return(CreateNew(
                           metaFeatureType,
                           Expression.Constant(feature.Name, typeof(string)),
                           Expression.Constant(feature.AddAnchor),
                           Expression.Constant(feature.Dictify)));
            }
        }