public static IEnumerable <BitSet> Choose(this BitSet b, int choose)
 {
     if (choose == 0)
     {
         // Choosing zero elements from any set gives the empty set.
         yield return(BitSet.Empty);
     }
     else if (b.Any())
     {
         // We are choosing at least one element from a set that has
         // a first element. Get the first element, and the set
         // lacking the first element.
         int    first = b.First();
         BitSet rest  = b.Remove(first);
         // These are the permutations that contain the first element:
         foreach (BitSet r in rest.Choose(choose - 1))
         {
             yield return(r.Add(first));
         }
         // These are the permutations that do not contain the first element:
         foreach (BitSet r in rest.Choose(choose))
         {
             yield return(r);
         }
     }
 }
Ejemplo n.º 2
0
 /// <summary>
 /// Recursive function that lifts the specified instruction.
 /// The input instruction is expected to a subexpression of the trueInst
 /// (so that all nullableVars are guaranteed non-null within this expression).
 ///
 /// Creates a new lifted instruction without modifying the input instruction.
 /// On success, returns (new lifted instruction, bitset).
 /// If lifting fails, returns (null, null).
 ///
 /// The returned bitset specifies which nullableVars were considered "relevant" for this instruction.
 /// bitSet[i] == true means nullableVars[i] was relevant.
 ///
 /// The new lifted instruction will have equivalent semantics to the input instruction
 /// if all relevant variables are non-null [except that the result will be wrapped in a Nullable{T} struct].
 /// If any relevant variable is null, the new instruction is guaranteed to evaluate to <c>null</c>
 /// without having any other effect.
 /// </summary>
 (ILInstruction, BitSet) DoLift(ILInstruction inst)
 {
     if (MatchGetValueOrDefault(inst, out ILVariable inputVar))
     {
         // n.GetValueOrDefault() lifted => n.
         BitSet foundIndices = new BitSet(nullableVars.Count);
         for (int i = 0; i < nullableVars.Count; i++)
         {
             if (nullableVars[i] == inputVar)
             {
                 foundIndices[i] = true;
             }
         }
         if (foundIndices.Any())
         {
             return(new LdLoc(inputVar)
             {
                 ILRange = inst.ILRange
             }, foundIndices);
         }
         else
         {
             return(null, null);
         }
     }
     else if (inst is Conv conv)
     {
         var(arg, bits) = DoLift(conv.Argument);
         if (arg != null)
         {
             if (conv.HasFlag(InstructionFlags.MayThrow) && !bits.All(0, nullableVars.Count))
             {
                 // Cannot execute potentially-throwing instruction unless all
                 // the nullableVars are arguments to the instruction
                 // (thus causing it not to throw when any of them is null).
                 return(null, null);
             }
             var newInst = new Conv(arg, conv.InputType, conv.InputSign, conv.TargetType, conv.CheckForOverflow, isLifted: true)
             {
                 ILRange = conv.ILRange
             };
             return(newInst, bits);
         }
     }
     else if (inst is BitNot bitnot)
     {
         var(arg, bits) = DoLift(bitnot.Argument);
         if (arg != null)
         {
             var newInst = new BitNot(arg, isLifted: true, stackType: bitnot.ResultType)
             {
                 ILRange = bitnot.ILRange
             };
             return(newInst, bits);
         }
     }
     else if (inst is BinaryNumericInstruction binary)
     {
         var(left, right, bits) = DoLiftBinary(binary.Left, binary.Right);
         if (left != null && right != null)
         {
             if (binary.HasFlag(InstructionFlags.MayThrow) && !bits.All(0, nullableVars.Count))
             {
                 // Cannot execute potentially-throwing instruction unless all
                 // the nullableVars are arguments to the instruction
                 // (thus causing it not to throw when any of them is null).
                 return(null, null);
             }
             var newInst = new BinaryNumericInstruction(
                 binary.Operator, left, right,
                 binary.LeftInputType, binary.RightInputType,
                 binary.CheckForOverflow, binary.Sign,
                 isLifted: true
                 )
             {
                 ILRange = binary.ILRange
             };
             return(newInst, bits);
         }
     }
     else if (inst is Comp comp && !comp.IsLifted && comp.Kind == ComparisonKind.Equality &&
              MatchGetValueOrDefault(comp.Left, out ILVariable v) &&
              NullableType.GetUnderlyingType(v.Type).IsKnownType(KnownTypeCode.Boolean) &&
              comp.Right.MatchLdcI4(0)
              )
     {
         // C# doesn't support ComparisonLiftingKind.ThreeValuedLogic,
         // except for operator! on bool?.
         var(arg, bits) = DoLift(comp.Left);
         Debug.Assert(arg != null);
         var newInst = new Comp(comp.Kind, ComparisonLiftingKind.ThreeValuedLogic, comp.InputType, comp.Sign, arg, comp.Right.Clone())
         {
             ILRange = comp.ILRange
         };
         return(newInst, bits);
     }
Ejemplo n.º 3
0
 /// <summary>
 /// Recursive function that lifts the specified instruction.
 /// The input instruction is expected to a subexpression of the trueInst
 /// (so that all nullableVars are guaranteed non-null within this expression).
 ///
 /// Creates a new lifted instruction without modifying the input instruction.
 /// On success, returns (new lifted instruction, bitset).
 /// If lifting fails, returns (null, null).
 ///
 /// The returned bitset specifies which nullableVars were considered "relevant" for this instruction.
 /// bitSet[i] == true means nullableVars[i] was relevant.
 ///
 /// The new lifted instruction will have equivalent semantics to the input instruction
 /// if all relevant variables are non-null [except that the result will be wrapped in a Nullable{T} struct].
 /// If any relevant variable is null, the new instruction is guaranteed to evaluate to <c>null</c>
 /// without having any other effect.
 /// </summary>
 (ILInstruction, BitSet) DoLift(ILInstruction inst)
 {
     if (MatchGetValueOrDefault(inst, out ILVariable inputVar))
     {
         // n.GetValueOrDefault() lifted => n.
         BitSet foundIndices = new BitSet(nullableVars.Count);
         for (int i = 0; i < nullableVars.Count; i++)
         {
             if (nullableVars[i] == inputVar)
             {
                 foundIndices[i] = true;
             }
         }
         if (foundIndices.Any())
         {
             return(new LdLoc(inputVar)
             {
                 ILRange = inst.ILRange
             }, foundIndices);
         }
         else
         {
             return(null, null);
         }
     }
     else if (inst is Conv conv)
     {
         var(arg, bits) = DoLift(conv.Argument);
         if (arg != null)
         {
             if (conv.HasFlag(InstructionFlags.MayThrow) && !bits.All(0, nullableVars.Count))
             {
                 // Cannot execute potentially-throwing instruction unless all
                 // the nullableVars are arguments to the instruction
                 // (thus causing it not to throw when any of them is null).
                 return(null, null);
             }
             var newInst = new Conv(arg, conv.InputType, conv.InputSign, conv.TargetType, conv.CheckForOverflow, isLifted: true)
             {
                 ILRange = conv.ILRange
             };
             return(newInst, bits);
         }
     }
     else if (inst is BinaryNumericInstruction binary)
     {
         var(left, leftBits)   = DoLift(binary.Left);
         var(right, rightBits) = DoLift(binary.Right);
         if (left != null && right == null && SemanticHelper.IsPure(binary.Right.Flags))
         {
             // Embed non-nullable pure expression in lifted expression.
             right = binary.Right.Clone();
         }
         if (left == null && right != null && SemanticHelper.IsPure(binary.Left.Flags))
         {
             // Embed non-nullable pure expression in lifted expression.
             left = binary.Left.Clone();
         }
         if (left != null && right != null)
         {
             var bits = leftBits ?? rightBits;
             if (rightBits != null)
             {
                 bits.UnionWith(rightBits);
             }
             if (binary.HasFlag(InstructionFlags.MayThrow) && !bits.All(0, nullableVars.Count))
             {
                 // Cannot execute potentially-throwing instruction unless all
                 // the nullableVars are arguments to the instruction
                 // (thus causing it not to throw when any of them is null).
                 return(null, null);
             }
             var newInst = new BinaryNumericInstruction(
                 binary.Operator, left, right,
                 binary.LeftInputType, binary.RightInputType,
                 binary.CheckForOverflow, binary.Sign,
                 isLifted: true
                 )
             {
                 ILRange = binary.ILRange
             };
             return(newInst, bits);
         }
     }
     return(null, null);
 }