/// <summary> /// Finds the range that contains "val", or an appropriate place in the list to /// insert a new range. /// </summary> /// <param name="val">Value to find.</param> /// <returns>The index of the matching element, or a negative value indicating /// the index to insert at. 2C doesn't support negative 0, so the insertion /// index will be incremented before negation.</returns> private int FindValue(int val) { int low = 0; int high = mRangeList.Count - 1; while (low <= high) { int mid = (low + high) / 2; TypedRange midRange = mRangeList[mid]; if (midRange.Contains(val)) { // found it return(mid); } else if (val < midRange.Low) { // too big, move the high end in high = mid - 1; } else if (val > midRange.High) { // too small, move the low end in low = mid + 1; } else { // WTF... list not sorted? throw new Exception("Bad binary search"); } } // Not found, insert before "low". return(-(low + 1)); }
/// <summary> /// Finds a range that contains searchVal, or identifies the one that immediately /// follows. The caller can determine which by checking to see if range.Low is /// greater than searchVal. /// </summary> /// <param name="searchVal">Value to find.</param> /// <param name="range">Result.</param> /// <returns>True if a valid range was returned.</returns> public bool GetContainingOrSubsequentRange(int searchVal, out TypedRange range) { int index = FindValue(searchVal); if (index >= 0) { // found a range that contains val range = mRangeList[index]; return(true); } // No matching range, so the index of the insertion point was returned. The // indexed range will have a "low" value that is greater than searchVal. If // we've reached the end of the list, the index will be past the end. index = -index - 1; if (index >= mRangeList.Count) { // reached the end of the list range = new TypedRange(-128, -128, -128); return(false); } range = mRangeList[index]; return(true); }
public void DebugDump(string name) { Debug.WriteLine(name + " has " + RangeCount + " ranges"); IEnumerator <TypedRange> iter = RangeListIterator; while (iter.MoveNext()) { TypedRange rng = iter.Current; Debug.WriteLine("[+{0:x6},+{1:x6}] ({2:x2})", rng.Low, rng.High, rng.Type); } }
/// <summary> /// Puts the next range in the list in mCurrentRange. /// </summary> /// <returns>True on success, false if we reached the end of the list.</returns> private bool GetNextRange() { mListIndex++; // increments to 0 on first invocation if (mListIndex == mSet.mRangeList.Count) { // no more ranges return(false); } mCurrentRange = mSet.mRangeList[mListIndex]; mCurrentVal = mCurrentRange.Low; return(true); }
/// <summary> /// Removes a value from the set. If the value is not present, nothing changes. /// </summary> /// <param name="val">Value to remove.</param> public void Remove(int val) { int listIndex = FindValue(val); if (listIndex < 0) { // not found return; } Count--; TypedRange rng = mRangeList[listIndex]; if (rng.Low == val && rng.High == val) { // Single-value range. Remove. mRangeList.RemoveAt(listIndex); } else if (rng.Low == val) { // We're at the low end, reduce range. rng.Low = val + 1; mRangeList[listIndex] = rng; } else if (rng.High == val) { // We're at the high end, reduce range. rng.High = val - 1; mRangeList[listIndex] = rng; } else { // We're in the middle, split the range. TypedRange next = new TypedRange(val + 1, rng.High, rng.Type); rng.High = val - 1; mRangeList[listIndex] = rng; mRangeList.Insert(listIndex + 1, next); } }
/// <summary> /// Adds or changes a value to the set. If the value is already present and has /// a matching type, nothing changes. /// </summary> /// <param name="val">Value to add.</param> /// <param name="type">Value's type.</param> public void Add(int val, int type) { int listIndex = FindValue(val); if (listIndex >= 0) { // Value is present in set, check type. if (mRangeList[listIndex].Type == type) { // It's a match, do nothing. return; } // Wrong type. Remove previous entry, then fall through to add new. Remove(val); listIndex = FindValue(val); // get insertion point } Count++; if (mRangeList.Count == 0) { // Empty list, skip the gymnastics. mRangeList.Add(new TypedRange(val, val, type)); return; } // Negate and decrement to get insertion index. This value may == Count if // the value is higher than all current members. listIndex = -listIndex - 1; if (listIndex > 0 && mRangeList[listIndex - 1].High == val - 1 && mRangeList[listIndex - 1].Type == type) { // Expand prior range. Check to see if it blends into next as well. if (listIndex < mRangeList.Count && mRangeList[listIndex].Low == val + 1 && mRangeList[listIndex].Type == type) { // Combine ranges. TypedRange prior = mRangeList[listIndex - 1]; TypedRange next = mRangeList[listIndex]; Debug.Assert(prior.High + 2 == next.Low); prior.High = next.High; mRangeList[listIndex - 1] = prior; mRangeList.RemoveAt(listIndex); } else { // Nope, just expand the prior range. TypedRange prior = mRangeList[listIndex - 1]; Debug.Assert(prior.High == val - 1); prior.High = val; mRangeList[listIndex - 1] = prior; } } else if (listIndex < mRangeList.Count && mRangeList[listIndex].Low == val + 1 && mRangeList[listIndex].Type == type) { // Expand next range. TypedRange next = mRangeList[listIndex]; Debug.Assert(next.Low == val + 1); next.Low = val; mRangeList[listIndex] = next; } else { // Nothing adjacent, add a new single-entry element. mRangeList.Insert(listIndex, new TypedRange(val, val, type)); } }
public TypedRangeEnumerator(TypedRange owner) { this.owner = owner; Reset(); }