private static IEnumerable <BigIntRange> EnumerateIncludedRanges(IEnumerable <BigIntRangeBound> sortedBounds) { BigInteger?prevBound = null; //only non-null when the previous bound is incomplete and needs the next bound before anything can be returned foreach (var bound in sortedBounds) { if (bound.Direction == Direction.Nowhere) { if (prevBound != null) { throw new InvalidOperationException("Underlying sorted set of range bounds is corrupt - previous bound (at value " + prevBound.Value + ") expected a matching closing bound next but current bound (at value " + bound.Bound + ") represents a single point."); } yield return(BigIntRange.Single(bound.Bound)); } else if (bound.Direction == Direction.Up) { if (prevBound != null) { throw new InvalidOperationException("Underlying sorted set of range bounds is corrupt - previous bound (at value " + prevBound.Value + ") expected a matching closing bound next but current bound (at value " + bound.Bound + ") represents the start of a new range."); } prevBound = bound.Bound; } else { if (prevBound == null) { throw new InvalidOperationException("Underlying sorted set of range bounds is corrupt - current bound (at value " + bound.Bound + ") represents the end of a range, but the previous bound was a complete range or there was no previous bound"); } yield return(BigIntRange.CreateStartEnd(prevBound.Value, bound.Bound)); prevBound = null; } } }
public bool TryGetSurroundingRange(BigInteger x, out BigIntRange range, out bool rangeIsIncluded) { BigIntRangeBound below; BigIntRangeBound above; if (TryGetSurroundingBounds(x, out below, out above)) { switch (below.Direction) { case Direction.Nowhere: range = BigIntRange.Single(below.Bound); //below == above rangeIsIncluded = true; return(true); case Direction.Down: switch (above.Direction) { case Direction.Down: throw new InvalidOperationException( "Underlying sorted set of range bounds is corrupt - the bound below or equal to " + nameof(x) + "=" + x + " " + "(at value " + below.Bound + ") represents the end of a range, but the bound above or equal " + "to " + nameof(x) + "=" + x + " (at value " + above.Bound + ") also represents the end of a range, meaning " + "this second range would have no starting value." ); case Direction.Nowhere: //Same behaviour as for Direction.Up case Direction.Up: if (BigInteger.Abs(below.Bound - above.Bound) >= 2) //If there is a gap between the bounds { range = BigIntRange.CreateStartEnd(below.Bound + 1, above.Bound - 1); rangeIsIncluded = false; return(true); } else { range = default(BigIntRange); rangeIsIncluded = default(bool); return(false); } default: break; } break; case Direction.Up: switch (above.Direction) { case Direction.Nowhere: throw new InvalidOperationException( "Underlying sorted set of range bounds is corrupt - the bound below or equal to " + nameof(x) + "=" + x + " " + "(at value " + below.Bound + ") represents the start of a range, so and end to this range is expected next, " + "but the bound above or equal to " + nameof(x) + "=" + x + " (at value " + above.Bound + ") represents a range " + "containing only single value." ); case Direction.Up: throw new InvalidOperationException( "Underlying sorted set of range bounds is corrupt - the bound below or equal to " + nameof(x) + "=" + x + " " + "(at value " + below.Bound + ") represents the end of a range, so and end to this range is expected next, " + "but the bound above or equal to " + nameof(x) + "=" + x + " (at value " + above.Bound + ") represents " + "the start of another range." ); case Direction.Down: range = BigIntRange.CreateStartEnd(below.Bound, above.Bound); rangeIsIncluded = true; return(true); default: break; } break; default: break; } } range = default(BigIntRange); rangeIsIncluded = default(bool); return(false); }