Back to notes -- Keyboard shortcut: 'u'        next -- Keyboard shortcut: 'n'  Slide program -- Keyboard shortcut: 't'    A slightly revised version of the Interval struct - with an error.Lecture 14 - slide 29 : 35
Program 1
/* There is a deliberately placed error in this program */

using System;
using System.Collections;

/* An interval with orientation */

public class IntervalAccessException: ApplicationException{
}

public struct Interval{

  private readonly int from, to;
  private bool empty;

  public Interval(int from, int to){
    this.empty = false;
    this.from = from;
    this.to = to;
  }
 
  /* Constructs an empty interval.
     This cannot be done elegantly by a constructor, because parameterless
     constructors cannot be used for structs */
  public static Interval MakeEmptyInterval (){
    Interval res = new Interval(); 
    res.empty = true;
    return res;
  }

  /* Assumed as a precondition that the interval is non-empty */
  public int From{
    get {if (this.Empty)
            throw new IntervalAccessException();
         else return from;}
  }

  /* Assumed as a precondition that the interval is non-empty */
  public int To{
     get {if (this.Empty)
            throw new IntervalAccessException();
         else return to;}
  }

  public bool Empty{
    get {return empty;}
  }

  /* Return the orientation of the interval. 
     Returns -1 in case from is larger than to,
     1 if from is small than to, and 0 is the interval is
     empty or singular. */
  private int Orientation {
   get{
    int res;

    if (empty)
      res = 0;
    else if (from < to)
      res = 1;
    else if (to < from)
      res = -1;
    else res = 0;

    return res;
   }
  }

  public int Length{
    get {return empty? 0: Math.Abs(to - from) + 1;}
  }

  /* Return element i of the interval, relative to its From edge.
     Like for arrays, the indexing is zero-bound */
  public int this[int i]{
    get {if (empty)
           throw new IndexOutOfRangeException("Error");
         else if (from <= to){
           if (i >= 0 && i <= Math.Abs(from-to))
               return from + i;
           else throw new IndexOutOfRangeException("Error"); }
         else if (from > to){
           if (i >= 0 && i <= Math.Abs(from-to))
               return from - i;
           else throw new IndexOutOfRangeException("Error"); }
         else throw new Exception("Should not happen"); }
  }

  /* The current interval determines the orientation of the resulting interval */
  public Interval OverlapWith (Interval other){
    // Enforce positively oriented intervals:
    Interval thisPI = (this.Orientation < 0) ? !this : this,
             otherPI = (other.Orientation < 0) ? !other : other,
             res;

    /* In the if-else chain we work with positively oriented intervals
       In such intervals From <= To: */

    if (thisPI.Empty || otherPI.Empty)                                 // both empty
         res = MakeEmptyInterval();
    else if (thisPI.From > otherPI.To || thisPI.To < otherPI.From)     // disjoint
         res = MakeEmptyInterval();
    else if (thisPI.From < otherPI.From && otherPI.To < thisPI.To)     // other inside this
         res = thisPI;
    else if (otherPI.From <= thisPI.From && thisPI.To <= otherPI.To)   // this inside other
         res = otherPI;
    else if (thisPI.From <= otherPI.From && otherPI.From <= thisPI.To) // this overlaps left border of other
         res = new Interval(otherPI.From, thisPI.To);
    else if (otherPI.From <= thisPI.From && thisPI.From <= otherPI.To) // other overlaps left border of this
         res = new Interval(thisPI.From, otherPI.To);
    else throw new Exception("Should not happen");

    // Reintroduce orientation:
    return (this.Orientation < 0) ? !res : res;
  }

  public static Interval operator +(Interval i, int j){
    return i.empty ? MakeEmptyInterval() : new Interval(i.From + j, i.To + j);
  }

  public static Interval operator +(int j, Interval i){
    return i.Empty ? MakeEmptyInterval() : new Interval(i.From + j, i.To + j);
  }

  public static Interval operator >>(Interval i, int j){
    return i.Empty ? MakeEmptyInterval() : new Interval(i.From, i.To + j);
  }

  public static Interval operator <<(Interval i, int j){
    return i.Empty ? MakeEmptyInterval() : new Interval(i.From + j, i.To);
  }

  public static Interval operator *(Interval i, int j){
    return i.Empty ? MakeEmptyInterval() : new Interval(i.From * j, i.To * j);
  }

  public static Interval operator *(int j, Interval i){
    return i.Empty ? MakeEmptyInterval() : new Interval(i.From * j, i.To * j);
  }

  public static Interval operator -(Interval i, int j){
    return i.Empty ? MakeEmptyInterval() : new Interval(i.From - j, i.To - j);
  }

  public static Interval operator !(Interval i){
    return i.Empty ? MakeEmptyInterval() : new Interval(i.To, i.From);
  }    

  public static explicit operator int[] (Interval i){
    int[] res = new int[i.Length];
    for (int j = 0; j < i.Length; j++) res[j] = i[j];
    return res; 
  }

  private class IntervalEnumerator: IEnumerator{
 
    private readonly Interval interval; 
    private int idx;

    public IntervalEnumerator (Interval i){
      this.interval = i;
      idx = -1;   // position enumerator outside range
    }
 
    public Object Current{ 
         get {return (interval.From < interval.To) ? 
                       interval.From + idx :
                       interval.From - idx;}
    }

    public bool MoveNext (){
      if (interval.Empty)
         return false;
      else if ( idx < Math.Abs(interval.To - interval.From))
         {idx++; return true;}
      else
         {return false;}
    }

    public void Reset(){
      idx = -1;         
    }
  }    
    
  public IEnumerator GetEnumerator (){
    return new IntervalEnumerator(this);
  }

}