public virtual void AddBitCombinations() { //AutoExpand enum into bit combinations //Note: We do this to make choosing the parameters easier and faster (ie: one time hit) //In addition we do this inorder to keep track of each combinations coverage //Must be an Enumerable type if (this.Type == null || !this.Type.IsEnum) { throw new ModelException(this, "BitMask can only be specified on a Enumerable type", null); } //Note: A simple (ripple) counter is the easiest solution // For example, Given 3 bits { A, B, C } the combinations are simply: // A, B, C Value // ------------------- // 0, 0, 0, = 0 (invalid, no bits on) // 0, 0, 1, = 1 // 0, 1, 0, = 2 // 0, 1, 1, = 3 // 1, 0, 0, = 4 // 1, 0, 1, = 5 // 1, 1, 0, = 6 // 1, 1, 1, = 7 ModelValues values = this.Values; Hashtable hash = new Hashtable(); //Automatic Dup collapsing int bits = values.Count; //bits int total = (int)Math.Pow(2, bits); //2^n for (int i = 1; i < total; i++) { int value = 0; //Calculate which bits are on for (int bit = 0; bit < bits; bit++) { int mask = 0x00000001 << bit; if ((i & mask) != 0) { value |= (int)values[bit].Value; } } //Note: We have to covert it back to the enum, inorder to call the method hash[value] = Enum.ToObject(this.Type, value); //Since 0 is skipped } //Update our list of values values.Clear(); foreach (object value in hash.Values) { values.Add(new ModelValue(value)); } }
///<summary>Finds all the model values except those that match the operator specified</summary> public virtual ModelValues FindOperator(ModelValueOperator op, bool include) { ModelValues found = new ModelValues(); foreach (ModelValue item in _list) { if ((item.Operator == op) == include) { found.Add(item); } } return(found); }
public ModelRequirement(ModelAction action, ModelRequirementAttribute attr, ModelVariable variable, ModelValue value) : base(action != null ? action.Model : null, attr) { //Action _action = action; //Variable if (variable != null) { _variable = variable; if (variable.BitMask) { this.BitMask = true; } } //if(_variable == null) // throw new ModelException(this, "An empty variable is not a valid requirement", null); //Only override the attr, if values are really specified if (value != null) { _values = new ModelValues(value); } //BitMask //TODO: Better place to expand this, (incase values added later). if (this.BitMask) { this.AddBitCombinations(); } //Infer dynamic variable(s) this.InferDynamicVariables(); //Requirements assoicated with actions, are not global. They are tied to that particular //instance of the model, and it's instance of state variables. However if not assoicated //with actions, the default behavior is that their global, they apply to all models //that contain that state variable, unless explicitly indicated otherwise. _global = (action == null); }
protected ModelValue DetermineParameterValue(ModelParameter parameter) { ModelValues values = new ModelValues(); values.Add(parameter.Values); //Parameter values, can be specified in numerous ways: // 1. Value list - simply choose one of them // 2. Expression - generate value that meets the criteria (ie: <, >, !=, etc) // 3. Variable - simply obtain the value by calling a method/field //#3. Variable - simply obtain the value by calling a method/field if (parameter.Variable != null) { object current = parameter.Variable.CachedValue; if (current is IEnumerable && !typeof(IEnumerable).IsAssignableFrom(parameter.Type)) { foreach (object v in (IEnumerable)current) { values.Add(new ModelValue(v)); } } else { values.Add(new ModelValue(current)); } } //First ensure we have a set of values/requirements to choose from if (values.Count <= 0) { throw new ModelException(parameter, "No values specified to choose from"); } //Note: Since we allow the operator on the individual values, this is a little more complex. //Note: We allow multiple operators, not just one, (ie: x > 5, < 10, and != 7). //This gives you great power and flexibility in expressions, but means we have to work a //little hard in determing a value that meets the requirements //#1. Value list - simply choose one of them //Note: Bitmask is already exploded into combinations ModelValues equalvalues = values.FindOperator(ModelValueOperator.Equal); //#2. Expression - generate value that meets the criteria (ie: <, >, !=, etc) //Note: Since we allow the operator on the individual values, this is a little more complex. //Note: We allow multiple operators, not just one, (ie: x > 5, < 10, and != 7). //This gives you great power and flexibility in expressions, but means we have to work a //little hard in determing a value that meets the requirements. int min = Int32.MinValue; int max = Int32.MaxValue; //Adjust our parameter, simplier to loop over all of them foreach (ModelValue value in values.FindOperator(ModelValueOperator.Equal, false).FindOperator(ModelValueOperator.NotEqual, false)) { //To keep this simple, we just support integers (for now). if (!(value.Value is int || value.Value is Nullable <int>)) { throw new ModelException(parameter, "Generated value range must be specified in terms of integers, not '" + value.Type + "'"); } //Simplify our life int v = (int)value.Value; //Adjust Max (if there is one) switch (value.Operator) { case ModelValueOperator.LessThanOrEqual: if (v < max) { max = v; } break; case ModelValueOperator.GreaterThanOrEqual: if (v > min) { min = v; } break; case ModelValueOperator.LessThan: if (v - 1 < max && v > Int32.MinValue /*prevent underflow*/) { max = v - 1; } break; case ModelValueOperator.GreaterThan: if (v + 1 > min && v < Int32.MaxValue /*prevent overflow*/) { min = v + 1; } break; } ; } //Choose a new value, within the specified range //Note: We retry in case it equals one of the existing invalid values (ie: !=) while (true) { ModelValue choice = null; if (equalvalues.Count > 0) { //Simple: Choose one of the specified values choice = new ModelValue(equalvalues.Choose(this).Value); } else { //Otherwise: Choose a value within in the range //Note: Random.Next = min <= x < max (so we have to add one) int index = _options.Random.Next(min, max < Int32.MaxValue ? max + 1 : max); //Prevent overflow choice = new ModelValue(index); } //As soon as we find a value, within the range, (and not in the invalid list), were done bool valid = true; foreach (ModelValue invalid in values.FindOperator(ModelValueOperator.NotEqual)) { if (invalid.Evaluate(choice.Value, ModelValueOperator.Equal)) { valid = false; } } if (valid) { return(choice); } } }