public bool Subtract(NumericRange other, out NumericRange reminder) { // If empty, nothing to subtract. reminder = new NumericRange(); if (this.IsEmpty || other.IsEmpty) { return(false); } // If disjoint, result is unchanged. if (IsDisjoint(other)) { return(false); } // If fully contained, result is empty. if (other.Contains(this)) { this.Lo = 0; this.Hi = 0; return(true); } // If only low edge is contained, the high segment is a reminder. if (other.Contains(this.Lo) && !other.Contains(this.Hi - 1)) { this.Lo = other.Hi; return(true); } // If only high edge is contained, the low segment is a reminder. if (other.Contains(this.Hi - 1) && !other.Contains(this.Lo)) { this.Hi = other.Lo; return(true); } // In this case, the other result is contained within, so the // subtraction produces two segments: 'this' keeps the low end, // and 'reminder' takes the high end. reminder.Hi = this.Hi; this.Hi = other.Lo; reminder.Lo = other.Hi; return(true); }
public static void Run() { NumericRange empty = new NumericRange(); Assert(empty.IsEmpty); NumericRange n = new NumericRange(); Assert(!n.Contains(0)); n.Hi = 1; Assert(n.Contains(0)); Assert(!n.Contains(1)); Assert(n.IsDisjoint(new NumericRange())); Assert(n.IsDisjoint(new NumericRange(1, 2))); NumericRange remainder; // Subtract - empty cases Assert(false == n.Subtract(empty, out remainder)); Assert(remainder.IsEmpty); Assert(false == empty.Subtract(n, out remainder)); // Subtract - disjoint Assert(false == NR(0, 3).Subtract(NR(3, 5), out remainder)); n = NR(0, 3); // Subtract - contained Assert(n.Subtract(NR(0, 4), out remainder)); Assert(n.IsEmpty); // Subtract - partial overlaps n = NR(10, 12); Assert(n.Subtract(NR(8, 11), out remainder)); Assert(n == NR(11, 12)); Assert(remainder.IsEmpty); n = NR(10, 12); Assert(n.Subtract(NR(11, 12), out remainder)); Assert(n == NR(10, 11)); Assert(remainder.IsEmpty); n = NR(10, 21); Assert(n.Subtract(NR(13, 17), out remainder)); Assert(n == NR(10, 13)); Assert(remainder == NR(17, 21)); // Coalesce - no-ops. NumericRange coalesced; n = NR(10, 21); Assert(false == n.TryCoalesce(NR(0, 9), out coalesced)); Assert(false == n.TryCoalesce(empty, out coalesced)); Assert(n.TryCoalesce(NR(0, 10), out coalesced)); Assert(coalesced == NR(0, 21)); n = NR(10, 21); Assert(n.TryCoalesce(NR(0, 100), out coalesced)); Assert(coalesced == NR(0, 100)); NumericRanges r = new NumericRanges(); Assert(r.IsEmpty); r.Add(0, 10); Assert(r.ToString() == "0-10"); r.Add(0, 4); Assert(r.ToString() == "0-10"); r.Add(20, 20); Assert(r.ToString() == "0-10"); r.Add(20, 30); Assert(r.ToString() == "0-10,20-30"); r.Add(10, 20); Assert(r.ToString() == "0-30"); r.Add(30, 32); Assert(r.ToString() == "0-32"); r.Clear(); Assert(r.ToString() == ""); r.Add(NR(0, 10)); r.Add(NR(20, 30)); var gaps = r.ListGaps(NR(0, 40)).ToList(); Assert(gaps[0] == NR(10, 20)); Assert(gaps[1] == NR(30, 40)); }