| /* 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);
}
} |