/// <summary> /// Calls the given transformation with the specified input /// </summary> /// <param name="input">The input for the transformation rule</param> /// <param name="transformationRule">The rule that should be applied</param> /// <param name="context">The callers context</param> /// <returns>The computation that handles this request</returns> public Computation CallTransformation(GeneralTransformationRule transformationRule, object[] input, IEnumerable context) { if (transformationRule == null) { throw new ArgumentNullException("transformationRule"); } if (input == null) { throw new ArgumentNullException("input"); } List <ITraceEntry> computations; if (!computationsMade.TryGetValue(input, out computations)) { computations = new List <ITraceEntry>(); computationsMade.Add(input, computations); } var originalTransformationRule = transformationRule; Computation comp; if (transformationRule.IsUnique) { comp = computations.OfType <Computation>().FirstOrDefault(cpt => cpt.TransformationRule == originalTransformationRule); } else { comp = null; } if (comp == null) { while (transformationRule.BaseRule != null) { transformationRule = transformationRule.BaseRule; } var compCon = CreateComputationContextInternal(input, transformationRule); comp = transformationRule.CreateComputation(input, compCon); if (comp == null) { return(null); } computations.Add(comp); AddTraceEntry(comp); compCon.DelayOutput(new OutputDelay()); CallDependencies(comp, true); HandleComputation(transformationRule, input, context, computations, originalTransformationRule, comp, compCon); if (transformationRule != originalTransformationRule) { comp = computations.OfType <Computation>().FirstOrDefault(cpt => cpt.TransformationRule == originalTransformationRule); } } return(comp); }
protected virtual string CreateLabel(object[] input, GeneralTransformationRule rule) { var sb = new StringBuilder(); sb.Append("["); if (input[0] != null) { sb.Append(input[0].ToString()); } else { sb.Append("(null)"); } for (int i = 1; i < input.Length; i++) { sb.Append(","); if (input[i] != null) { sb.Append(input[i].ToString()); } else { sb.Append("(null)"); } } sb.Append("], "); sb.Append(rule.ToString()); return sb.ToString(); }
private void AddChild(GeneralTransformationRule rule) { if (Children == null) { Children = new List <GeneralTransformationRule>(); } Children.Add(rule); }
private ComputationContext CreateComputationContextInternal(object[] input, GeneralTransformationRule rule) { var compCon = CreateComputationContext(input, rule); compCon.DelayOutputAtLeast(rule.OutputDelayLevel); compCon.DelayTransformationAtLeast(rule.TransformationDelayLevel); return(compCon); }
protected sealed override ComputationContext CreateComputationContext(object[] input, GeneralTransformationRule rule) { var context = new TracingComputationContext(CreateId(input, rule), this); nodes.AppendFormat(" <Node Id=\"{0}\" Label=\"{1}\"/>", context.Id, CreateLabel(input, rule)); nodes.AppendLine(); return context; }
internal ITransformationRuleDependency CallForEachInternal(GeneralTransformationRule rule, Predicate <Computation> filter, Func <Computation, IEnumerable <object[]> > selector, Action <object, IEnumerable> persistor, bool needOutput) { if (rule == null) { throw new ArgumentNullException("rule"); } return(rule.DependMany(filter, selector, this, persistor, false, needOutput)); }
private void HandleDelayedComputation(Computation computation, ITransformationContext context, OutputDelay delay) { var inCollection = Selector(computation); if (inCollection != null) { if (Persistor != null) { Type listType = (typeof(List <>)).MakeGenericType(DependencyTransformation.OutputType); IList list = System.Activator.CreateInstance(listType) as IList; MultipleResultAwaitingPersistor delayPersistor = new MultipleResultAwaitingPersistor() { List = list, Persistor = Persistor }; if (context.IsThreadSafe) { Parallel.ForEach(inCollection, dependencyInput => { HandleDelayedDependencyInput(computation, context, list, delayPersistor, dependencyInput); }); } else { foreach (var dependencyInput in inCollection) { HandleDelayedDependencyInput(computation, context, list, delayPersistor, dependencyInput); } } delay.Persistors.Add(delayPersistor); } else { if (context.IsThreadSafe) { Parallel.ForEach(inCollection, dependencyInput => { GeneralTransformationRule dependent = DependencyTransformation; var comp2 = context.CallTransformation(dependent, dependencyInput); computation.MarkRequireInternal(comp2, ExecuteBefore, this); }); } else { foreach (var dependencyInput in inCollection) { GeneralTransformationRule dependent = DependencyTransformation; var comp2 = context.CallTransformation(dependent, dependencyInput); computation.MarkRequireInternal(comp2, ExecuteBefore, this); } } } } }
/// <summary> /// Marks the current transformation rule instantiating for the specified rule /// </summary> /// <param name="rule">The base transformation rule</param> /// <param name="filter">A method that filters the possible computations</param> /// <remarks>Note that in this version, the filter method is also responsible for checking the types!</remarks> public void MarkInstantiatingFor(GeneralTransformationRule rule, Predicate <Computation> filter) { if (rule == null) { throw new ArgumentNullException("rule"); } rule.AddChild(this); AddBase(rule, filter); }
/// <summary> /// Creates a new computation for the given transformation rule with the given input arguments /// </summary> /// <param name="transformationRule">The transformation rule responsible for the transformation of the input data</param> /// <param name="context">The transformation context, in which the computation is done</param> protected Computation(GeneralTransformationRule transformationRule, IComputationContext context) { if (transformationRule == null) throw new ArgumentNullException("transformationRule"); if (context == null) throw new ArgumentNullException("context"); TransformationRule = transformationRule; Context = context; context.ConnectWith(this); }
/// <summary> /// Traces the computation based upon the specified input with the specified transformation rule /// </summary> /// <param name="rule">The transformation rule the object was transformed with</param> /// <returns>The computation or null, if there was none</returns> /// <param name="input">The input arguments</param> public virtual IEnumerable<ITraceEntry> TraceIn(GeneralTransformationRule rule, params object[] input) { if (rule == null) throw new ArgumentNullException("rule"); if (input == null || input.Length != rule.InputType.Length) return Enumerable.Empty<ITraceEntry>(); return from ITraceEntry c in Computations where c.TransformationRule == rule && IsInputArray(c, input) select c; }
/// <summary> /// Calls the given transformation with the specified input /// </summary> /// <param name="input">The input for the transformation rule</param> /// <param name="transformationRule">The rule that should be applied</param> /// <param name="context">The callers context</param> /// <returns>The computation that handles this request</returns> public Computation CallTransformation(GeneralTransformationRule transformationRule, object[] input, IEnumerable context) { if (transformationRule == null) throw new ArgumentNullException("transformationRule"); if (input == null) throw new ArgumentNullException("input"); List<ITraceEntry> computations; if (!computationsMade.TryGetValue(input, out computations)) { computations = new List<ITraceEntry>(); computationsMade.Add(input, computations); } var originalTransformationRule = transformationRule; while (transformationRule.BaseRule != null) { transformationRule = transformationRule.BaseRule; } Computation comp; if (transformationRule.IsUnique) { comp = computations.OfType<Computation>().FirstOrDefault(cpt => cpt.TransformationRule == transformationRule); if (comp != null && transformationRule != originalTransformationRule) { transformationRule = originalTransformationRule; while (computations.OfType<Computation>().FirstOrDefault(cpt => cpt.TransformationRule == transformationRule.BaseRule) == null) { transformationRule = transformationRule.BaseRule; } comp = computations.OfType<Computation>().FirstOrDefault(cpt => cpt.TransformationRule == transformationRule); } } else { comp = null; } if (comp == null) { var compCon = CreateComputationContextInternal(input, transformationRule); comp = transformationRule.CreateComputation(input, compCon); if (comp == null) return null; computations.Add(comp); AddTraceEntry(comp); compCon.DelayOutput(new OutputDelay()); CallDependencies(comp, true); HandleComputation(transformationRule, input, context, computations, originalTransformationRule, comp, compCon); } return comp; }
/// <summary> /// Traces all computations with any inputs that math the given filters with the specified transformation rule /// </summary> /// <param name="rule">The transformation rule</param> /// <returns>A collection with all computations made under these circumstances</returns> public virtual IEnumerable <ITraceEntry> TraceAllIn(GeneralTransformationRule rule) { if (rule == null) { throw new ArgumentNullException("rule"); } return(from ITraceEntry c in Computations where c.TransformationRule == rule select c); }
/// <summary> /// Traces the computations of the specified inputs with the specified transformation rules /// </summary> /// <param name="rule">The transformation rules that transformed the specified inputs</param> /// <param name="inputs">A collection of input arguments</param> /// <returns>A collection of computations</returns> public virtual IEnumerable <ITraceEntry> TraceManyIn(GeneralTransformationRule rule, IEnumerable <object[]> inputs) { if (rule == null) { throw new ArgumentNullException("rule"); } if (inputs.IsNullOrEmpty()) { return(Enumerable.Empty <ITraceEntry>()); } return(Computations.Where(c => c.TransformationRule == rule && inputs.Any(input => input != null && input.Length == rule.InputType.Length && IsInputArray(c, input)))); }
private void AddBase(GeneralTransformationRule rule, Predicate <Computation> filter) { if (BaseRule == null) { BaseRule = rule; BaseFilter = filter; } else { throw new InvalidOperationException(Resources.ErrMarkInstantiatingForOneRuleAtMost); } }
/// <summary> /// Traces the computation based upon the specified input with the specified transformation rule /// </summary> /// <param name="rule">The transformation rule the object was transformed with</param> /// <returns>The computation or null, if there was none</returns> /// <param name="input">The input arguments</param> public override IEnumerable <ITraceEntry> TraceIn(GeneralTransformationRule rule, params object[] input) { if (rule == null) { throw new ArgumentNullException("rule"); } List <ITraceEntry> comps; if (computationsMade.TryGetValue(input, out comps)) { return(comps.Where(c => c.TransformationRule == rule)); } return(Enumerable.Empty <ITraceEntry>()); }
/// <summary> /// Marks the current transformation rule instantiating for the specified rule /// </summary> /// <param name="rule">The base transformation rule</param> public void MarkInstantiatingFor(GeneralTransformationRule rule) { if (rule == null) { throw new ArgumentNullException("rule"); } if (rule.InputType.IsAssignableArrayFrom(InputType) && (rule.OutputType == OutputType || rule.OutputType.IsAssignableFrom(OutputType) || OutputType.IsInterface)) { MarkInstantiatingFor(rule, null); } else { throw new InvalidOperationException(Resources.ErrMarkInstantiatingForMustInherit); } }
/// <summary> /// Requires the given transformation rule /// </summary> /// <param name="rule">The transformation rule that should be required</param> /// <remarks>This version Always takes the input parameter as input for the dependent transformations. Thus, this method will throw an exception, if the types do not match</remarks> public void Call(GeneralTransformationRule rule) { if (rule == null) { throw new ArgumentNullException("rule"); } if (rule.InputType.IsAssignableArrayFrom(InputType)) { Depend(null, c => c.CreateInputArray(), rule, null, false, false); } else { throw new InvalidOperationException(Resources.ErrRequiresTransNoSelectorMustInherit); } }
/// <summary> /// Creates a new computation for the given transformation rule with the given input arguments /// </summary> /// <param name="transformationRule">The transformation rule responsible for the transformation of the input data</param> /// <param name="context">The transformation context, in which the computation is done</param> protected Computation(GeneralTransformationRule transformationRule, IComputationContext context) { if (transformationRule == null) { throw new ArgumentNullException("transformationRule"); } if (context == null) { throw new ArgumentNullException("context"); } TransformationRule = transformationRule; Context = context; context.ConnectWith(this); }
/// <summary> /// Traces the computation based upon the specified input with the specified transformation rule /// </summary> /// <param name="rule">The transformation rule the object was transformed with</param> /// <returns>The computation or null, if there was none</returns> /// <param name="input">The input arguments</param> public virtual IEnumerable <ITraceEntry> TraceIn(GeneralTransformationRule rule, params object[] input) { if (rule == null) { throw new ArgumentNullException("rule"); } if (input == null || input.Length != rule.InputType.Length) { return(Enumerable.Empty <ITraceEntry>()); } return(from ITraceEntry c in Computations where c.TransformationRule == rule && IsInputArray(c, input) select c); }
/// <summary> /// Traces all computations with any inputs that math the given filters with the specified transformation rule /// </summary> /// <param name="rule">The transformation rule</param> /// <returns>A collection with all computations made under these circumstances</returns> public override IEnumerable <ITraceEntry> TraceAllIn(GeneralTransformationRule rule) { if (rule == null) { throw new ArgumentNullException("rule"); } List <ITraceEntry> comps; if (computationsByTransformationRule.TryGetValue(rule, out comps)) { return(comps.AsReadOnly()); } else { return(Enumerable.Empty <Computation>()); } }
private static void ReorderStack(GeneralTransformationRule originalTransformationRule, Computation comp, Stack <GeneralTransformationRule> ruleStack) { var testTransformationRule = originalTransformationRule; var missingStack = new Stack <GeneralTransformationRule>(); while (!ruleStack.Contains(testTransformationRule)) { missingStack.Push(testTransformationRule); testTransformationRule = testTransformationRule.BaseRule; } while (ruleStack.Peek() != testTransformationRule) { ruleStack.Pop(); if (ruleStack.Count == 0) { throw new InvalidOperationException("The rule stack from the transformation rule did not contain the base rule of the computation"); } } while (missingStack.Count > 0) { testTransformationRule = missingStack.Pop(); ruleStack.Push(testTransformationRule); } while (!testTransformationRule.IsLeafTransformation) { var found = false; foreach (var next in testTransformationRule.Children) { if (next.IsInstantiating(comp)) { testTransformationRule = next; ruleStack.Push(next); found = true; break; } } if (!found) { break; } } }
/// <summary> /// Marks the current transformation rule instantiating for the specified rule /// </summary> /// <param name="filter">The filter that should filter the inputs where this transformation rule is marked instantiating</param> /// <param name="rule">The transformation rule</param> public void MarkInstantiatingFor(GeneralTransformationRule rule, Predicate<object[]> filter) { if (rule == null) throw new ArgumentNullException("rule"); if (rule.InputType.IsAssignableArrayFrom(InputType) && (rule.OutputType == typeof(void))) { Require(rule); if (filter != null) { MarkInstantiatingFor(rule, o => InputType.IsInstanceArrayOfType(o) && filter(o)); } else { MarkInstantiatingFor(rule, InputType.IsInstanceArrayOfType); } } else { throw new InvalidOperationException(Resources.ErrMarkInstantiatingMustInherit); } }
/// <summary> /// Traces the computations of the specified inputs with the specified transformation rules /// </summary> /// <param name="rule">The transformation rules that transformed the specified inputs</param> /// <param name="inputs">A collection of input arguments</param> /// <returns>A collection of computations</returns> public override IEnumerable <ITraceEntry> TraceManyIn(GeneralTransformationRule rule, IEnumerable <object[]> inputs) { if (rule == null) { throw new ArgumentNullException("rule"); } if (inputs == null) { return(Enumerable.Empty <ITraceEntry>()); } List <ITraceEntry> result = new List <ITraceEntry>(); foreach (var input in inputs) { List <ITraceEntry> comps; if (computationsMade.TryGetValue(input, out comps)) { result.AddRange(comps.Where(c => c.TransformationRule == rule)); } } return(result); }
/// <summary> /// Transforms the input argument into an output using the provided transformation /// </summary> /// <param name="inputs">The input arguments as an array. This must not be null. The correct amount of parameters depends on the rule to start with.</param> /// <param name="inputContext">The context object in which the transformation is run</param> /// <param name="startRule">The start rule to begin with (must not be null)</param> /// <param name="context">The transformation context (must not be null)</param> /// <returns>The transformation computations</returns> public static IEnumerable<Computation> TransformMany(IEnumerable<object[]> inputs, IEnumerable inputContext, GeneralTransformationRule startRule, ITransformationEngineContext context) { if (context == null) throw new ArgumentNullException("context"); if (inputs == null) throw new ArgumentNullException("inputs"); if (startRule == null) throw new InvalidOperationException("Could not find transaction rule to start with."); if (!context.Transformation.IsInitialized) throw new InvalidOperationException("Could not initialize transformation"); var patternObjects = new List<ITransformationPatternContext>(); foreach (var pattern in context.Transformation.Patterns) { var obj = pattern.CreatePattern(context); if (obj != null) patternObjects.Add(obj); } var list = new List<Computation>(); foreach (var input in inputs) { var comp = context.CallTransformation(startRule, input, inputContext); list.Add(comp); if (!comp.IsDelayed) { context.Outputs.Add(comp.Output); } else { comp.OutputInitialized += (o,e) => context.Outputs.Add(comp.Output); } } context.ExecutePending(); foreach (var pattern in patternObjects) { pattern.Begin(); context.ExecutePending(); } foreach (var pattern in patternObjects) { pattern.Finish(); } return list; }
private void HandleDelayedDependencyInput(Computation computation, ITransformationContext context, IList list, MultipleResultAwaitingPersistor delayPersistor, object[] dependencyInput) { GeneralTransformationRule dependent = DependencyTransformation; var comp2 = context.CallTransformation(dependent, dependencyInput); if (!comp2.IsDelayed) { if (comp2.Output != null) { if (context.IsThreadSafe) { lock (list) { list.Add(comp2.Output); } } else { list.Add(comp2.Output); } } } else { computation.DelayOutputAtLeast(comp2.Context.MinOutputDelayLevel); delayPersistor.WaitFor(comp2); } if (ExecuteBefore) { computation.DelayTransformationAtLeast(comp2.Context.MinTransformDelayLevel); } else { comp2.DelayTransformationAtLeast(computation.Context.MinTransformDelayLevel); } }
private static void ReorderStack(GeneralTransformationRule originalTransformationRule, Computation comp, Stack<GeneralTransformationRule> ruleStack) { var testTransformationRule = originalTransformationRule; var missingStack = new Stack<GeneralTransformationRule>(); while (!ruleStack.Contains(testTransformationRule)) { missingStack.Push(testTransformationRule); testTransformationRule = testTransformationRule.BaseRule; } while (ruleStack.Peek() != testTransformationRule) { ruleStack.Pop(); if (ruleStack.Count == 0) throw new InvalidOperationException("The rule stack from the transformation rule did not contain the base rule of the computation"); } while (missingStack.Count > 0) { testTransformationRule = missingStack.Pop(); ruleStack.Push(testTransformationRule); } while (!testTransformationRule.IsLeafTransformation) { var found = false; foreach (var next in testTransformationRule.Children) { if (next.IsInstantiating(comp)) { testTransformationRule = next; ruleStack.Push(next); found = true; break; } } if (!found) break; } }
/// <summary> /// Calls the transformation dependency for the given computation /// </summary> /// <param name="computation">The computation that this dependency is to be called</param> public override void HandleDependency(Computation computation) { if (computation == null) { throw new ArgumentNullException("computation"); } if (computation.IsDelayed && NeedOutput) { computation.OutputInitialized += CallComputation; return; } if (Filter == null || Filter(computation)) { var context = computation.TransformationContext; if (Selector != null) { if (computation.IsDelayed) { //case delayed var delay = computation.OutputDelay; if (!NeedOutput) { object[] dependencyInput = Selector(computation); if (dependencyInput != null) { GeneralTransformationRule dependent = DependencyTransformation; var comp2 = context.CallTransformation(dependent, dependencyInput); if (Persistor != null) { if (!comp2.IsDelayed) { delay.Persistors.Add(new SingleItemPersistor() { Persistor = Persistor, Output = comp2.Output }); } else { computation.DelayOutputAtLeast(comp2.Context.MinOutputDelayLevel); var delayPersistor = new SingleResultAwaitingPersistor(Persistor); delayPersistor.WaitFor(comp2); delay.Persistors.Add(delayPersistor); } } else // persistor is null { if (ExecuteBefore) { if (comp2.IsDelayed) { computation.DelayOutputAtLeast(comp2.Context.MinOutputDelayLevel); } } } computation.MarkRequireInternal(comp2, ExecuteBefore, this); } } } else // not delayed { // case output is already created var output = computation.Output; object[] dependencyInput = Selector(computation); if (dependencyInput != null) { GeneralTransformationRule dependent = DependencyTransformation; var comp2 = context.CallTransformation(dependent, dependencyInput); if (Persistor != null) { if (!comp2.IsDelayed) { Persistor(output, comp2.Output); } else { var delay = new SingleResultAwaitingPersistor(Persistor, computation.Output); delay.WaitFor(comp2); } } computation.MarkRequireInternal(comp2, ExecuteBefore, this); } } } } }
/// <summary> /// Handles the computation internally, i.e. calls dependencies, creates output, manages delays, etc /// </summary> /// <param name="transformationRule">The transformation rule</param> /// <param name="input">The input elements for this computation</param> /// <param name="context">The transformation context</param> /// <param name="computations">The computations for the input</param> /// <param name="originalTransformationRule">The transformation rule of the original call</param> /// <param name="comp">The computation</param> /// <param name="compCon">The computation context</param> private void HandleComputation(GeneralTransformationRule transformationRule, object[] input, IEnumerable context, List<ITraceEntry> computations, GeneralTransformationRule originalTransformationRule, Computation comp, ComputationContext compCon) { // The transformation output is only generated when we are handling the base transformation rule, // because this is always required if (compCon.IsDelayed) { Stack<Computation> dependantComputes = new Stack<Computation>(); var ruleStack = Transformation.ComputeInstantiatingTransformationRulePath(comp); if (transformationRule != originalTransformationRule) { ReorderStack(originalTransformationRule, comp, ruleStack); } var delayLevel = comp.Context.MinOutputDelayLevel; var computes = new List<Computation>(); Computation lastComp = null; while (ruleStack.Count > 0) { var rule = ruleStack.Pop(); var comp2 = FindOrCreateDependentComputation(input, computations, comp, dependantComputes, rule); // in case comp2 is not yet handled, a delay does not yet exist and thus // DelayLevel < minDelayLevel delayLevel = Math.Max(delayLevel, Math.Max(comp2.OutputDelayLevel, comp2.Context.MinOutputDelayLevel)); if (lastComp != null) { lastComp.SetBaseComputation(comp2); } lastComp = comp2; computes.Add(comp2); } // delay the call of dependencies // this prevents the issue arising from computations calling their parents that come later in the stack foreach (var comp2 in dependantComputes) { CallDependencies(comp2, true); } if (delayLevel <= currentOutputDelay) { var createRule = computes[0]; // Generate the output var output = createRule.CreateOutput(context); for (int i = computes.Count - 1; i >= 0; i--) { computes[i].InitializeOutput(output); } if (callTransformations) { for (int i = computes.Count - 1; i >= 0; i--) { computes[i].Transform(); } } } else { //Save computations into Delay Delay(delayLevel, computes, context); } if (!callTransformations) { for (int i = computes.Count - 1; i >= 0; i--) { AddToComputationOrder(computes[i], currentTransformationDelay); } } for (int i = computes.Count - 1; i >= 0; i--) { dependencyCallQueue.Enqueue(computes[i]); } } }
private ComputationContext CreateComputationContextInternal(object[] input, GeneralTransformationRule rule) { var compCon = CreateComputationContext(input, rule); compCon.DelayOutputAtLeast(rule.OutputDelayLevel); compCon.DelayTransformationAtLeast(rule.TransformationDelayLevel); return compCon; }
/// <summary> /// Traces the computation based upon the specified input with the specified transformation rule /// </summary> /// <param name="rule">The transformation rule the object was transformed with</param> /// <returns>The computation or null, if there was none</returns> /// <param name="input">The input arguments</param> public override IEnumerable<ITraceEntry> TraceIn(GeneralTransformationRule rule, params object[] input) { if (rule == null) throw new ArgumentNullException("rule"); List<ITraceEntry> comps; if (computationsMade.TryGetValue(input, out comps)) { return comps.Where(c => c.TransformationRule == rule); } return Enumerable.Empty<ITraceEntry>(); }
protected virtual ComputationContext CreateComputationContext(object[] input, GeneralTransformationRule rule) { return(new ComputationContext(this)); }
/// <summary> /// Handles the computation internally, i.e. calls dependencies, creates output, manages delays, etc /// </summary> /// <param name="transformationRule">The transformation rule</param> /// <param name="input">The input elements for this computation</param> /// <param name="context">The transformation context</param> /// <param name="computations">The computations for the input</param> /// <param name="originalTransformationRule">The transformation rule of the original call</param> /// <param name="comp">The computation</param> /// <param name="compCon">The computation context</param> private void HandleComputation(GeneralTransformationRule transformationRule, object[] input, IEnumerable context, List <ITraceEntry> computations, GeneralTransformationRule originalTransformationRule, Computation comp, ComputationContext compCon) { // The transformation output is only generated when we are handling the base transformation rule, // because this is always required if (compCon.IsDelayed) { Stack <Computation> dependantComputes = new Stack <Computation>(); var ruleStack = Transformation.ComputeInstantiatingTransformationRulePath(comp); if (transformationRule != originalTransformationRule) { ReorderStack(originalTransformationRule, comp, ruleStack); } var delayLevel = comp.Context.MinOutputDelayLevel; var computes = new List <Computation>(); Computation lastComp = null; while (ruleStack.Count > 0) { var rule = ruleStack.Pop(); var comp2 = FindOrCreateDependentComputation(input, computations, comp, dependantComputes, rule); // in case comp2 is not yet handled, a delay does not yet exist and thus // DelayLevel < minDelayLevel delayLevel = Math.Max(delayLevel, Math.Max(comp2.OutputDelayLevel, comp2.Context.MinOutputDelayLevel)); if (lastComp != null) { lastComp.SetBaseComputation(comp2); } lastComp = comp2; computes.Add(comp2); } // delay the call of dependencies // this prevents the issue arising from computations calling their parents that come later in the stack foreach (var comp2 in dependantComputes) { CallDependencies(comp2, true); } if (delayLevel <= currentOutputDelay) { var createRule = computes[0]; // Generate the output var output = createRule.CreateOutput(context); for (int i = computes.Count - 1; i >= 0; i--) { computes[i].InitializeOutput(output); } if (callTransformations) { for (int i = computes.Count - 1; i >= 0; i--) { computes[i].Transform(); } } } else { //Save computations into Delay Delay(delayLevel, computes, context); } if (!callTransformations) { for (int i = computes.Count - 1; i >= 0; i--) { AddToComputationOrder(computes[i], currentTransformationDelay); } } for (int i = computes.Count - 1; i >= 0; i--) { dependencyCallQueue.Enqueue(computes[i]); } } }
internal ITransformationRuleDependency DependMany(Predicate<Computation> filter, Func<Computation, IEnumerable<object[]>> selector, GeneralTransformationRule transformation, Action<object, IEnumerable> persistor, bool executeBefore, bool needOutput) { if (transformation == null) throw new ArgumentNullException("transformation"); if (selector == null) throw new ArgumentNullException("selector"); var dependency = new MultipleDependency() { Filter = filter, Selector = selector, Persistor = persistor, BaseTransformation = this, DependencyTransformation = transformation, ExecuteBefore = executeBefore, NeedOutput = needOutput }; Dependencies.Add(dependency); return dependency; }
/// <summary> /// Transforms the input argument into an output using the provided transformation /// </summary> /// <param name="inputs">The input arguments as an array. This must not be null. The correct amount of parameters depends on the rule to start with.</param> /// <param name="inputContext">The context object in which the transformation is run</param> /// <param name="startRule">The start rule to begin with (must not be null)</param> /// <param name="context">The transformation context (must not be null)</param> /// <returns>The transformation computations</returns> public static IEnumerable <Computation> TransformMany(IEnumerable <object[]> inputs, IEnumerable inputContext, GeneralTransformationRule startRule, ITransformationEngineContext context) { if (context == null) { throw new ArgumentNullException("context"); } if (inputs == null) { throw new ArgumentNullException("inputs"); } if (startRule == null) { throw new InvalidOperationException("Could not find transaction rule to start with."); } if (!context.Transformation.IsInitialized) { throw new InvalidOperationException("Could not initialize transformation"); } var patternObjects = new List <ITransformationPatternContext>(); foreach (var pattern in context.Transformation.Patterns) { var obj = pattern.CreatePattern(context); if (obj != null) { patternObjects.Add(obj); } } var list = new List <Computation>(); foreach (var input in inputs) { var comp = context.CallTransformation(startRule, input, inputContext); list.Add(comp); if (!comp.IsDelayed) { context.Outputs.Add(comp.Output); } else { comp.OutputInitialized += (o, e) => context.Outputs.Add(comp.Output); } } context.ExecutePending(); foreach (var pattern in patternObjects) { pattern.Begin(); context.ExecutePending(); } foreach (var pattern in patternObjects) { pattern.Finish(); } return(list); }
/// <summary> /// Calls the given transformation with the specified input /// </summary> /// <param name="context">The current transformation context</param> /// <param name="transformationRule">The rule that should be applied</param> /// <param name="input">The input for the transformation rule</param> /// <returns>The computation that handles this request</returns> public static Computation CallTransformation(this ITransformationContext context, GeneralTransformationRule transformationRule, params object[] input) { return context.CallTransformation(transformationRule, input, null); }
/// <summary> /// Traces all computations with any inputs that math the given filters with the specified transformation rule /// </summary> /// <param name="rule">The transformation rule</param> /// <returns>A collection with all computations made under these circumstances</returns> public virtual IEnumerable<ITraceEntry> TraceAllIn(GeneralTransformationRule rule) { if (rule == null) throw new ArgumentNullException("rule"); return from ITraceEntry c in Computations where c.TransformationRule == rule select c; }
protected virtual string CreateId(object[] input, GeneralTransformationRule rule) { counter++; return "node" + counter.ToString(); }
/// <summary> /// Traces the computations of the specified inputs with the specified transformation rules /// </summary> /// <param name="rule">The transformation rules that transformed the specified inputs</param> /// <param name="inputs">A collection of input arguments</param> /// <returns>A collection of computations</returns> public virtual IEnumerable<ITraceEntry> TraceManyIn(GeneralTransformationRule rule, IEnumerable<object[]> inputs) { if (rule == null) throw new ArgumentNullException("rule"); if (inputs.IsNullOrEmpty()) return Enumerable.Empty<ITraceEntry>(); return Computations.Where(c => c.TransformationRule == rule && inputs.Any(input => input != null && input.Length == rule.InputType.Length && IsInputArray(c, input))); }
/// <summary> /// Creates a new mocked computation /// </summary> /// <param name="input">The input for the mocked computation</param> /// <param name="rule">The transformation rule for the mocked computation</param> /// <param name="context">The transformation context</param> public MockComputation(object[] input, GeneralTransformationRule rule, ITransformationContext context) : this(input, rule, new ComputationContext(context)) { }
/// <summary> /// Creates a new mocked computation /// </summary> /// <param name="input">The input for the mocked computation</param> /// <param name="rule">The transformation rule for the mocked computation</param> /// <param name="context">The transformation context</param> public MockComputation(object[] input, GeneralTransformationRule rule, IComputationContext context) : base(rule, context) { inputs = input; }
internal ITransformationRuleDependency CallForEachInternal(GeneralTransformationRule rule, Predicate<Computation> filter, Func<Computation, IEnumerable<object[]>> selector, Action<object, IEnumerable> persistor, bool needOutput) { if (rule == null) throw new ArgumentNullException("rule"); return rule.DependMany(filter, selector, this, persistor, false, needOutput); }
protected virtual ComputationContext CreateComputationContext(object[] input, GeneralTransformationRule rule) { return new ComputationContext(this); }
private void AddBase(GeneralTransformationRule rule, Predicate<Computation> filter) { if (BaseRule == null) { BaseRule = rule; BaseFilter = filter; } else { throw new InvalidOperationException(Resources.ErrMarkInstantiatingForOneRuleAtMost); } }
private Computation FindOrCreateDependentComputation(object[] input, List <ITraceEntry> computations, Computation comp, Stack <Computation> dependantComputes, GeneralTransformationRule rule) { var comp2 = computations.Where(cmp => cmp.TransformationRule == rule).OfType <Computation>().FirstOrDefault(); if (comp2 == null) { comp2 = rule.CreateComputation(input, comp.Context); computations.Add(comp2); AddTraceEntry(comp2); dependantComputes.Push(comp2); } return(comp2); }
private bool HandleNonDelayedPersistedDependencyInput(Computation computation, ITransformationContext context, IList list, MultipleResultAwaitingPersistor delayPersistor, GeneralTransformationRule dependent, object[] dependencyInput) { var needDelayedPersistor = false; var comp2 = context.CallTransformation(dependent, dependencyInput); if (!comp2.IsDelayed) { if (comp2.Output != null) { var lockList = context.IsThreadSafe; if (lockList) { lock (list) { list.Add(comp2.Output); } } else { list.Add(comp2.Output); } } } else { needDelayedPersistor = true; delayPersistor.WaitFor(comp2); } computation.MarkRequireInternal(comp2, ExecuteBefore, this); return(needDelayedPersistor); }
/// <summary> /// Traces the computations of the specified inputs with the specified transformation rules /// </summary> /// <param name="rule">The transformation rules that transformed the specified inputs</param> /// <param name="inputs">A collection of input arguments</param> /// <returns>A collection of computations</returns> public override IEnumerable<ITraceEntry> TraceManyIn(GeneralTransformationRule rule, IEnumerable<object[]> inputs) { if (rule == null) throw new ArgumentNullException("rule"); if (inputs == null) return Enumerable.Empty<ITraceEntry>(); List<ITraceEntry> result = new List<ITraceEntry>(); foreach (var input in inputs) { List<ITraceEntry> comps; if (computationsMade.TryGetValue(input, out comps)) { result.AddRange(comps.Where(c => c.TransformationRule == rule)); } } return result; }
/// <summary> /// Traces all computations with any inputs that math the given filters with the specified transformation rule /// </summary> /// <param name="rule">The transformation rule</param> /// <returns>A collection with all computations made under these circumstances</returns> public override IEnumerable<ITraceEntry> TraceAllIn(GeneralTransformationRule rule) { if (rule == null) throw new ArgumentNullException("rule"); List<ITraceEntry> comps; if (computationsByTransformationRule.TryGetValue(rule, out comps)) { return comps.AsReadOnly(); } else { return Enumerable.Empty<Computation>(); } }
private void AddChild(GeneralTransformationRule rule) { if (Children == null) Children = new List<GeneralTransformationRule>(); Children.Add(rule); }
protected ParallelComputationContext CreateComputationContext(GeneralTransformationRule rule) { var compCon = new ParallelComputationContext(this); compCon.DelayOutputAtLeast(rule.OutputDelayLevel); compCon.DelayTransformationAtLeast(rule.TransformationDelayLevel); return compCon; }
/// <summary> /// Requires the given transformation rule /// </summary> /// <param name="rule">The transformation rule that should be required</param> /// <remarks>This version Always takes the input parameter as input for the dependent transformations. Thus, this method will throw an exception, if the types do not match</remarks> public void Call(GeneralTransformationRule rule) { if (rule == null) throw new ArgumentNullException("rule"); if (rule.InputType.IsAssignableArrayFrom(InputType)) { Depend(null, c => c.CreateInputArray(), rule, null, false, false); } else { throw new InvalidOperationException(Resources.ErrRequiresTransNoSelectorMustInherit); } }
/// <summary> /// Marks the current transformation rule instantiating for the specified rule /// </summary> /// <param name="rule">The base transformation rule</param> public void MarkInstantiatingFor(GeneralTransformationRule rule) { if (rule == null) throw new ArgumentNullException("rule"); if (rule.InputType.IsAssignableArrayFrom(InputType) && (rule.OutputType == OutputType || rule.OutputType.IsAssignableFrom(OutputType) || OutputType.IsInterface)) { MarkInstantiatingFor(rule, null); } else { throw new InvalidOperationException(Resources.ErrMarkInstantiatingForMustInherit); } }
private void HandleNonDelayedComputation(Computation computation, ITransformationContext context) { var output = computation.Output; var inCollection = Selector(computation); if (inCollection != null) { if (Persistor != null) { Type listType = (typeof(List <>)).MakeGenericType(DependencyTransformation.OutputType); IList list = System.Activator.CreateInstance(listType) as IList; MultipleResultAwaitingPersistor delayPersistor = new MultipleResultAwaitingPersistor() { List = list, Persistor = Persistor, Target = output }; bool needDependencyPersistor = false; GeneralTransformationRule dependent = DependencyTransformation; if (context.IsThreadSafe) { Parallel.ForEach(inCollection, dependencyInput => { if (HandleNonDelayedPersistedDependencyInput(computation, context, list, delayPersistor, dependent, dependencyInput)) { needDependencyPersistor = true; } }); } else { foreach (var dependencyInput in inCollection) { if (HandleNonDelayedPersistedDependencyInput(computation, context, list, delayPersistor, dependent, dependencyInput)) { needDependencyPersistor = true; } } } if (!needDependencyPersistor) { Persistor(output, list); } } else { GeneralTransformationRule dependent = DependencyTransformation; if (context.IsThreadSafe) { Parallel.ForEach(inCollection, dependencyInput => { var comp2 = context.CallTransformation(dependent, dependencyInput); computation.MarkRequireInternal(comp2, ExecuteBefore, this); }); } else { foreach (var dependencyInput in inCollection) { var comp2 = context.CallTransformation(dependent, dependencyInput); computation.MarkRequireInternal(comp2, ExecuteBefore, this); } } } } }
/// <summary> /// Marks the current transformation rule instantiating for the specified rule /// </summary> /// <param name="rule">The base transformation rule</param> /// <param name="filter">A method that filters the possible computations</param> /// <remarks>Note that in this version, the filter method is also responsible for checking the types!</remarks> public void MarkInstantiatingFor(GeneralTransformationRule rule, Predicate<Computation> filter) { if (rule == null) throw new ArgumentNullException("rule"); rule.AddChild(this); AddBase(rule, filter); }
/// <summary> /// Calls the given transformation with the specified input /// </summary> /// <param name="context">The current transformation context</param> /// <param name="transformationRule">The rule that should be applied</param> /// <param name="input">The input for the transformation rule</param> /// <returns>The computation that handles this request</returns> public static Computation CallTransformation(this ITransformationContext context, GeneralTransformationRule transformationRule, params object[] input) { return(context.CallTransformation(transformationRule, input, null)); }
/// <summary> /// Creates a new mocked computation /// </summary> /// <param name="input">The input for the mocked computation</param> /// <param name="rule">The transformation rule for the mocked computation</param> /// <param name="context">The transformation context</param> /// <param name="output">The output for the transformation</param> public MockComputation(object[] input, GeneralTransformationRule rule, IComputationContext context, object output) : base(rule, context) { inputs = input; InitializeOutput(output); }
internal ITransformationRuleDependency DependMany(Predicate <Computation> filter, Func <Computation, IEnumerable <object[]> > selector, GeneralTransformationRule transformation, Action <object, IEnumerable> persistor, bool executeBefore, bool needOutput) { if (transformation == null) { throw new ArgumentNullException("transformation"); } if (selector == null) { throw new ArgumentNullException("selector"); } var dependency = new MultipleDependency() { Filter = filter, Selector = selector, Persistor = persistor, BaseTransformation = this, DependencyTransformation = transformation, ExecuteBefore = executeBefore, NeedOutput = needOutput }; Dependencies.Add(dependency); return(dependency); }
private Computation FindOrCreateDependentComputation(object[] input, List<ITraceEntry> computations, Computation comp, Stack<Computation> dependantComputes, GeneralTransformationRule rule) { lock (computations) { var comp2 = computations.Where(cmp => cmp.TransformationRule == rule).OfType<Computation>().FirstOrDefault(); if (comp2 == null) { comp2 = rule.CreateComputation(input, comp.Context); computations.Add(comp2); AddTraceEntry(comp2); dependantComputes.Push(comp2); } return comp2; } }