DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Snippets has posted 5883 posts at DZone. View Full User Profile

Statically Enforced Range Types In Scala

12.11.2007
| 2310 views |
  • submit to reddit
        Cute piece of code for statically checking array index accesses. 

package ranges;

class Range(val start : Int, val end : Int){
  if (start >= end) throw new IndexOutOfBoundsException();

  def checkRange(min : Int, max : Int){
    if (min < start || max > end) throw new IndexOutOfBoundsException();
  }

  def inBounds(x : Int) : Index = unsafeFromInt(Math.min(end - 1, Math.max(x, start)));
  def checkBounds (x : Int) : Index = if (x < start || x >= end) throw new IndexOutOfBoundsException() else unsafeFromInt(x);

  private[Range] def unsafeFromInt (i : Int) = Index(i); // Separated into a method for refactoring and unsafe declaration.

  val range = start until end;
  val length = end - start;

  val maxIndex = unsafeFromInt(end - 1);
  val minIndex = unsafeFromInt(start);
  val indices = range.map(unsafeFromInt(_));

  trait Slice[T] extends Iterable[T] {
    def apply(i : Index) : T = unsafeApply(i);     
    def update(i : Index, t : T) = unsafeUpdate(i, t);

    private[Range] def unsafeApply(i : Int) : T;
    private[Range] def unsafeUpdate(i : Int, t : T) : Unit;

    def elements = range.elements.map(unsafeApply(_)); 
  } 

  class ArraySlice[T](array : Array[T]) extends Slice[T]{
    if (length < end) throw new IndexOutOfBoundsException();
    private[Range] def unsafeApply(i : Int) = array(i);
    private[Range] def unsafeUpdate(i : Int, t : T) : Unit = array(i) = t;

    override def foreach(f : T => Unit) = for (val i <- range) array(i);
  }

  class CheckedArray[T] extends Slice[T]{
    private val array = new Array[T](length);
    
    private[Range] def unsafeApply(i : Int) = array(i - start);
    private[Range] def unsafeUpdate(i : Int, t : T) : Unit = array(i - start) = t;
    
    override def foreach(f : T => Unit) = array.foreach(f);
  }

  implicit def toInteger(i : Index) = i.toInt;

  case class Index private[Range] (val toInt : Int){
    def max(y : Index) = unsafeFromInt(Math.max(this, y));
    def min(y : Index) = unsafeFromInt(Math.min(this, y));
    def mid(y : Index) = unsafeFromInt((this + y) >>> 1);
    def opposite = unsafeFromInt(end + start - 1 - this);
  }; 
}