/* CookieJarArray implementation of the CookieJar ADT in Scala H. Conrad Cunningham Version #1: 23 March 2010 Version #1a: 19 Sept 2011 Add range on "end" to Implementation Invariant 123456789012345678901234567890123456789012345678901234567890123456789012345678 */ /* Class CookieJarArray implements the CookieJar ADT using Scala's Array data structure and an integer counter to implement the jar (mathematical bag) of cookies. The cookies occur in the array with indexes less than the counter the same number of times they do in the cookie jar. IMPLEMENTATION INVARIANT: (0 <= end <= jar.length) && (ForAll c : c IN CookieType :: OCCURRENCES(c,Bag) == jar.slice(0,end).filter(_==c).length ) A production implementation of this class should probably have the initial array size and the expansion factor as parameters to the constructor, with an alternate constructor using the default values. */ class CookieJarArray[CookieType] extends CookieJar[CookieType] { /* CookieJar's bag model is implemented by an Array "jar" of cookies and counter "end" that refers to the next empty position in the array. The bag is represented by the portion of the array with indices 0 to end-1. */ private var jar = new Array[CookieType](CookieJarArray.DEF_JAR_SIZE) private var end = 0 def putIn(cookie: CookieType) { if (end >= jar.length) expandArray jar(end) = cookie end += 1 } def eat(cookie: CookieType) { var in = end-1 while (in >= 0 && jar(in) != cookie) // search back from end in -= 1 // to minimize copy if (in >= 0) { for (i <- in to end-2) jar(i) = jar(i+1) end -= 1 // jar(end) = null <-- left this out to test logic related to "end" } else throw new RuntimeException( "Attempt to eat cookie \"" + cookie + "\", which is not in the jar.") } def isEmpty: Boolean = (end == 0) def has(cookie: CookieType): Boolean = { for ( i <- 0 to end-1 ) if (jar(i) == cookie) return true false } /* Redefine toString to return form "CookieJar(e1,e2,e3,...,en)" with all elements of bag in arbitrary order. */ override def toString = "CookieJar(" + jar.slice(0,end).mkString(",") + ")" /* Internal method called to increase the array size when array jar is full and new cookies need to be added. It doubles the size on each call. */ private def expandArray { // println("Expanding cookie jar array from size = " + end) val newJar = new Array[CookieType](2 * jar.length) for (i <- 0 to jar.length-1) newJar(i) = jar(i) jar = newJar } } /* CookieJarArray companion object to hold configuration paramters of the CookieJarArray class. */ object CookieJarArray { val DEF_JAR_SIZE = 1 // make very small to aid in testing }